Introduction

Dans le cadre de notre projet de statistiques, nous travaillerons sur un jeu de données environnementales. Ce jeu de données est composé de plusieurs fichiers qui contiennent des informations sur les oiseaux, les stations de mesure, les caractéristiques des oiseaux, leurs régimes alimentaires et la biodiversité.

Ce rapport a pour objectif de présenter les différentes analyses que nous avons réalisées sur ces données. Il est composé de trois parties principales dans lesquelles nous explorons les relations entre la diversité des espèces d’oiseaux, l’artificialisation des sols et la distance avec le centre-ville de Bordeaux. Nous avons également étudié les régimes alimentaires des oiseaux et les modes de nidification en fonction de certaines zones géographiques.

Vous trouverez des cartes, des graphiques, des tableaux, un sankie plot ainsi qu’un sunburst plot qui nous permettront de découvrir la mesure de la biodiversité.

L’ensemble de ces données sont tirées du travail des membres de l’INRAE unité BioGeCo et du bureau de télédetection I-sea.

Vous trouverez de nombreux résultats comme plusieurs courbes de diversité révélant la baisse significative de diversité dans les lieux les plus artificialisés. Vous trouverez également l’entièreté de notre cheminement pour arriver à nos résultats statistiques, notamment concernant la distribution des espèces d’oiseaux observées en Gironde, mais aussi des statistiques multivariées et descriptives.

Nous vous invitons à découvrir l’ensemble de nos analyses et à explorer les différentes visualisations que nous avons réalisées pour mieux comprendre les relations entre les différentes variables de notre jeu de données. Toutes nos visualisations sont interactives et vous permettent de zoomer, de déplacer et de cliquer sur les différents éléments pour obtenir plus d’informations. Cela vous permettra d’avoir une expérience plus immersive et vous permettra de créer vos propres analyses, en parallèle à celles réalisées par nos soins.

Exploration des données

Pour commencer, nous chargeons les données et nous les explorons pour mieux comprendre leur structure. Dans un premier temps, nous allons ajouter une colonne à notre DataFrame qui contient les noms latins des oiseaux afin de facilliter les analyses par la suite.

oiseaux <- read.csv("data/birds/Oiseaux_up_to_2023.csv", header = TRUE, sep = "\t")
# CRÉER UNE NOUVELLE COLONNE DANS LE DATAFRAME OISEAUX QUI CONTIENT LE NOM LATIN DE L'OISEAU
my_split <- function(array, str = " \\| ") {
  out <- rep(NA, length(array))
  for (i in 1:length(array)) {
    out[i] <- unlist(strsplit(array[i], str))[1]
  }
  return(out)
}

only_latin <- my_split(as.vector(oiseaux$Nom_Taxon_Cite))

oiseaux$latin <- only_latin
oiseaux$annee <- as.numeric(substr(oiseaux$Date, 1, 4))

Par la suite, nous allons explorer les données pour mieux comprendre la distribution des espèces d’oiseaux observées. Voici un tableau qui montre les 10 espèces d’oiseaux les plus fréquemment observées dans l’ensemble des données.

# LES ESPÈCES D'OISEAUX LES PLUS FRÉQUENTES OBSERVÉES DANS L'ENSEMBLE DES DONNÉES
as.data.frame(sort(table(oiseaux$latin), decreasing = TRUE)[1:10])

Nous allons maintenant explorer la fréquence des espèces d’oiseaux observées dans l’ensemble des données par année. Voici, par ordre alphabétique, le tableau mettant en évidence cette fréquence.

# FRÉQUENCE DES ESPÈCES D'OISEAUX OBSERVÉES DANS L'ENSEMBLE DES DONNÉES PAR ANNÉE
Annee <- my_split(as.vector(oiseaux$Date), str = "-")
oiseaux$Annee <- as.factor(Annee)
as.data.frame.matrix(table(oiseaux$latin, oiseaux$Annee))

Mesure de la diversité

Dans cette partie, nous allons explorer la mesure de la diversité à à l’aide de plusieurs entropies. Nous nous intéresserons uniquement au MOS11, c’est à dire les surfaces artificialisées. On prend comme buffer size 500m.

Dans un premier temps, nous allons utiliser la proportion d’espèces différentes observées dans une station pour mesurer la diversité. Dans un deuxième temps, nous allons utiliser l’entropie de Shannon et enfin l’indice de Simpson.

## Analyse de diversité par rapport à MOS11 et par année

denombrement <- oiseaux %>%
  group_by(Code_Maille, annee, latin) %>%
  summarise(sum = sum(Denombrement_min, na.rm = TRUE), .groups = "drop") %>%
  arrange(desc(Code_Maille))

denombrement$p <- rep(NA, nrow(denombrement))
for (i in 1:nrow(denombrement)) {
  numerator <- denombrement$sum[i]
  denominator <-
    sum(denombrement$sum[which(denombrement$Code_Maille == denombrement$Code_Maille[i]
                               & denombrement$annee == denombrement$annee[i])])
  denombrement$p[i] <- numerator / denominator
}

index <- denombrement %>%
  group_by(Code_Maille, annee = factor(annee)) %>%
  summarise(D1 = sum(p > 0, na.rm = TRUE),
            D2 = exp(-sum(p * log(p))),
            D3 = 1 / sum(p^2), .groups = "drop") %>%
  arrange(desc(Code_Maille))

LUP <- read.csv("data/birds/LandUsePer_BM_2023_cartoISea.csv", header = TRUE)
index$MOS11 <- rep(NA, nrow(index))
for (i in 1:nrow(index)) {
  index$MOS11[i] <- LUP$MOS11[which(index$Code_Maille[i] == LUP$ID & LUP$BufferSize == 500)]
}

Proportion d’espèces

Voici le graphique qui montre la relation entre la diversité et MOS11 pour chaque année expliquée par la proportion d’espèces.

ggplot(index, aes(x = MOS11, y = D1, color = as.factor(annee))) +
  geom_point(size = 2) +
  geom_smooth(method = "auto", se = TRUE, color = "black", alpha = 0.2) +
  labs(title = "Proportion d’espèces en fonction de MOS11",
       x = "MOS11",
       y = "Proportion d'espèces") +
  theme_minimal() +
  labs(colour = "Année") +
  theme(legend.position = "bottom")

Indice de Shanon

Ceci est le graphique qui montre la relation entre la diversité et MOS11 pour chaque année expliquée par l’entropie de Shannon.

ggplot(index, aes(x = MOS11, y = D2, color = as.factor(annee))) +
  geom_point(size = 2) +
  geom_smooth(method = "auto", se = TRUE, color = "black", alpha = 0.2) +
  labs(title = "Indice de Shanon en fonction de MOS11",
       x = "MOS11",
       y = "Indice de Shanon") +
  theme_minimal() +
  labs(colour = "Année") +
  theme(legend.position = "bottom")

Indice de Simpson

Ceci est le graphique qui montre la relation entre la diversité et MOS11 pour chaque année expliquée par l’indice de Simpson.

ggplot(index, aes(x = MOS11, y = D3, color = as.factor(annee))) +
  geom_point(size = 2) +
  geom_smooth(method = "auto", se = TRUE, color = "black", alpha = 0.2) +
  labs(title = "Indice de Simpson en fonction de MOS11",
       x = "MOS11",
       y = "Indice de Simpson") +
  theme_minimal() +
  labs(colour = "Année") +
  theme(legend.position = "bottom")

La tendance globale est l’augmentation de la diversité au début de la courbe jusqu’à atteindre un maximum puis une baisse quand le MOS11 augmente davantage. C’est-à-dire que, moins les sols sont artificialisés, plus la diversité est grande avec une diversité maximale atteinte quand le milieu est à la fois artificialisé mais présente également des surfaces non artificialisées.

Notre deuxième partie se portera sur l’analyse de la diversité des espèces d’oiseaux en fonction de la distance avec le centre-ville de Bordeaux. On observera une tendance de diversité par rapport à la distance de la maille avec le centre ville qui diffère légèrement par rapport aux résultats ci-dessus. Pour ce faire, nous allons calculer toutes les distances de chaque maille à PeyBerland, qui sera notre point référent pour le centre.

Tendance de diversité par rapport à la distance avec le centre-ville

PeyBerland <- data.frame("Latitude" = 44.838168, "Longitude" = -0.578803)

# On convertit les coordonnées de PeyBerland en sf

PeyBerland <- st_as_sf(PeyBerland, coords = c("Longitude", "Latitude"), crs = 4326)

# On va créer un dataframe qui contient les coordonnées de toutes les stations code_maille

coordinates <- st_as_sf(LUP, coords = c("X", "Y"), crs = 2154)

# On va transformer les coordonnées de 2154 à 4326

coordinates <- st_transform(coordinates, crs = 4326)

# On va calculer les distances entre les stations et le centre ville PeyBerland

coordinates$Distance <- st_distance(coordinates, PeyBerland)

On ajoute les distances à nos données de diversité.

index$Distance <- rep(NA, nrow(index))
for (i in 1:nrow(index)) {
  index$Distance[i] <- coordinates$Distance[which(index$Code_Maille[i] == coordinates$ID & coordinates$BufferSize == 500)]
}

par(mfrow = c(1, 3))

Pour faire l’analyse, on utilise les trois mesures de diversité que nous avons utilisées précédemment.

Mesure de la diversité

Proportion d’espèces

Voici la courbe de diversité expliquée par la proportion d’espèces.

ggplot(index, aes(x = Distance, y = D1, color = as.factor(annee))) +
  geom_point(size = 2) +
  geom_smooth(method = "auto", se = TRUE, color = "black", alpha = 0.2) +
  labs(title = "Proportion d'espèces en fonction de la distance au centre-ville",
       x = "Distance",
       y = "Proportion d'espèces") +
  theme_minimal() +
  labs(colour = "Année") +
  theme(legend.position = "bottom")

Indice de Shanon

Voici la courbe de diversité expliquée par l’entropie de Shannon.

ggplot(index, aes(x = Distance, y = D2, color = as.factor(annee))) +
  geom_point(size = 2) +
  geom_smooth(method = "auto", se = TRUE, color = "black", alpha = 0.2) +
  labs(title = "Indice de Shanon en fonction de la distance au centre-ville",
       x = "Distance",
       y = "Indice de Shanon") +
  theme_minimal() +
  labs(colour = "Année") +
  theme(legend.position = "bottom")

Indice de Simpson

Voici la courbe de diversité expliquée par l’indice de Simpson.

ggplot(index, aes(x = Distance, y = D3, color = as.factor(annee))) +
  geom_point(size = 2) +
  geom_smooth(method = "auto", se = TRUE, color = "black", alpha = 0.2) +
  labs(title = "Indice de Simpson en fonction de la distance au centre-ville",
       x = "Distance",
       y = "Indice de Simpson") +
  theme_minimal() +
  labs(colour = "Année") +
  theme(legend.position = "bottom")

La tendance globale est l’augmentation de la diversité au début de la courbe jusqu’à atteindre un maximum puis une baisse quand la distance avec le centre-ville augmente davantage. Nous pouvons voir que pour nos trois mesures de diversité, le pic est atteint à environ 9km. La diversité est donc plus grande lorsque la maille se trouver à environ 9km du centre-ville. Nous retrouvons donc la même observation qu’avec la variable d’artificialisation des sols (MOSS11), car l’artificialisation des sols et la distance avec le centre ville sont positivement corrélées (peut-etre essayer de mesurer la correlation entre ces deux variables sur nos données)

Par la suite, l’objectif va être de comprendre pourquoi ce pic de diversité des espèces est observé à ce pourcentage d’artificialisation. Pour ce faire, nous allons introduire un nouveau jeu de données sur les caractéristiques des espèces d’oiseaux. Nous allons combiner ce jeu de données avec les autres jeux de données afin d’en tirer des analyses, principalement grâce à des cartes interactives.

oiseaux <- read.csv("data/birds/Oiseaux_up_to_2023.csv", header = TRUE, sep = "\t")
LUP <- read.csv("data/birds/LandUsePer_BM_2023_cartoISea.csv", header = TRUE)
# CRÉER UNE NOUVELLE COLONNE DANS LE DATAFRAME OISEAUX QUI CONTIENT LE NOM LATIN DE L'OISEAU
# LE NOM LATIN EST LE PREMIER NOM DE LA COLONNE "Nom_Taxon_Cite
# SI LE NOM CONTIENT UN "|", LE NOM LATIN EST LE PREMIER NOM AVANT LE "|"

# Diviser les noms
my_split <- function(array, str = " \\| ") {
  out <- rep(NA, length(array))
  for (i in 1:length(array)) {
    out[i] <- unlist(strsplit(array[i], str))[1]
  }
  return(out)
}

# Tester la fonction
only_latin <- my_split(as.vector(oiseaux$Nom_Taxon_Cite))

# On ajoute la nouvelle colonne au dataframe
oiseaux$latin <- only_latin

Voici le tableau qui représente le MOS11 pour chaque station de mesure. Cette mesure nous indique à quel point le sol est artificialisé.

# CRÉER UNE NOUVELLE COLONNE DANS LE DATAFRAME OISEAUX QUI CONTIENT LA VALEUR MOS11 DU POINT
filter <- LUP$BufferSize == 500
LUP_500_MOS11 <- LUP[filter, c("Geometry", "ID", "X", "Y", "BufferSize", "MOS11")]
rownames(LUP_500_MOS11) <- 1:nrow(LUP_500_MOS11)
LUP_500_MOS11[, c("ID", "MOS11")]
MOS11 <- rep(NA, nrow(oiseaux))
for (i in 1:nrow(oiseaux)) {
  MOS11[i] <- which(oiseaux$Code_Maille[i] == LUP_500_MOS11$ID)
}

# Ajouter la colonne MOS11 au dataframe
oiseaux$MOS11 <- LUP_500_MOS11$MOS11[MOS11]

Analyses intéractives et géographiques

oiseaux <- read.csv("data/birds/Oiseaux_up_to_2023.csv", header = TRUE, sep = "\t")
# CREATE A NEW COLUMN IN THE OISEAUX DATAFRAME THAT CONTAINS THE LATIN NAME OF THE BIRD
my_split <- function(array, str = " \\| ") {
  out <- rep(NA, length(array))
  for (i in 1:length(array)) {
    out[i] <- unlist(strsplit(array[i], str))[1]
  }
  return (out)
}

only_latin <- my_split(as.vector(oiseaux$Nom_Taxon_Cite))
# length(unique(only_latin)) == length(unique(oiseaux$Code_Ref))

oiseaux$latin <- only_latin
oiseaux$annee <- as.numeric(substr(oiseaux$Date, 1, 4))

denombrement <- oiseaux %>%
  group_by(Code_Maille, annee, latin) %>%
  summarise(sum = sum(Denombrement_min, na.rm = TRUE), .groups = 'drop') %>%
  arrange(desc(Code_Maille))

denombrement$p <- rep(NA, nrow(denombrement))
for (i in 1:nrow(denombrement)) {
  numerator <- denombrement$sum[i]
  denominator <- 
    sum(denombrement$sum[which(denombrement$Code_Maille == denombrement$Code_Maille[i] 
                               & denombrement$annee == denombrement$annee[i])])
  denombrement$p[i] <- numerator / denominator
}

index <- denombrement %>%
  group_by(Code_Maille, annee = factor(annee)) %>%
  summarise(D1 = sum(p > 0, na.rm = TRUE), 
            D2 = exp(-sum(p*log(p))), 
            D3 = 1 / sum(p^2), .groups = 'drop') %>%
  arrange(desc(Code_Maille))

LUP <- read.csv("data/birds/LandUsePer_BM_2023_cartoISea.csv", header = TRUE)
index$MOS11 <- rep(NA, nrow(index))
for (i in 1:nrow(index)) {
  index$MOS11[i] <- LUP$MOS11[which(index$Code_Maille[i] == LUP$ID & LUP$BufferSize == 1000)]
}


traits <- read.csv("data/birds/traits-statut-IUCN-biodivercite.csv", header = TRUE)
cite <- read.csv("data/birds/BiodiverCite_sites.csv", header = TRUE, sep=";")

#on veut traiter la table dénombrement qu'on appelera denombrementCarte où il restera pour chaque maille et pour chaque année le top 3 des oiseaux les plus observés sans la variable p

denombrementCarte <- denombrement %>%
  group_by(Code_Maille, annee) %>%
  top_n(3, sum) %>%
  arrange(Code_Maille, annee, desc(sum)) %>%
  ungroup() %>%
  select(-p)


#on veut changer cette table pour faire apparaitre de nouvelles colonnes pour qu'il y ait : une ligne par maille et par année, et pour chaque oiseau, le nombre d'individus observés

denombrementCarte <- denombrementCarte %>%
  pivot_wider(names_from = latin, values_from = sum, values_fill = 0)


#on veut ajouter les colonnes geometry, buffer size et MOS11 à la table denombrementCarte et pas les autres

denombrementCarte <- left_join(denombrementCarte, LUP, by = c("Code_Maille" = "ID"))

#on enlève les colonnes : MOS1, MOS2, MOS3, MOS4, MOS5, MOS6, MOS7, MOS8, MOS9, MOS10, MOS12, MOS13, MOS14

denombrementCarte <- denombrementCarte %>%
  select(-c(MOS1, MOS2, MOS3, MOS4, MOS5, MOS6, MOS7, MOS8, MOS9, MOS10, MOS12, MOS13, MOS14))

# On garde que les lignes ou BufferSize == 500
denombrementCarte <- denombrementCarte %>%
  filter(BufferSize == 500)

denombrementCarte <- st_as_sf(denombrementCarte, coords = c("X", "Y"), crs = 2154)
denombrementCarte <- st_transform(denombrementCarte, crs = 4326)

# On garde seuelement les valeurs ou annee = 2018

denombrementCarte <- denombrementCarte %>%
  filter(annee == 2023)

denombrementCarte

Grâce à ce tableau, nous pouvons voir comment les données sont structurées et remarquer notamment qu’il classe le nombre d’oiseaux par maille et par année.

Dans la suite de ce rapport vous trouverez des analyses géographiques et interactives qui vous permettront de visualiser comment les oiseaux de la Gironde évoluent en fonction de l’artificialisation des sols. Vous y trouverez des analyses sur les régimes alimentaires des oiseaux, les niveaux de spécialisation des oiseaux en fonction de leur habitat (Maille).

Voici la carte interactive qui montre les mailles de mesure et les oiseaux les plus observés dans chaque maille. Nous vous invitons à cliquer sur les cercles pour obtenir toutes les informations sur les oiseaux.

# On garder que les colonnes qui nous intéressent, cad code_site et Nom_lieu

cite <- read.csv("data/birds/BiodiverCite_sites.csv", header = TRUE, sep=";")
cite <- cite %>%
  select(code_site, Nom_lieu)

#On join les deux tables cite et denombrementCarte

denombrementCarte <- left_join(denombrementCarte, cite, by = c("Code_Maille" = "code_site"))

# Créer une chaîne de caractères pour les popups avec le top trois des oiseaux ayant la plus grande valeur
denombrementCarte$popup_text <- paste0("<strong>Maille:</strong> ", denombrementCarte$Nom_lieu, "<br>",
                                      "<strong>Année:</strong> ", denombrementCarte$annee, "<br>",
                                      "<strong>Top 3 des oiseaux:</strong>", "<br>")

dataframe <- as.data.frame(denombrementCarte)

# On enleve les colonnes Code_Maille, annee, BufferSize, MOS11, Geometry, geometry
dataframe <- dataframe %>%
  select(-c(Code_Maille, annee, BufferSize, MOS11, Geometry, geometry, Nom_lieu))

# Ajouter les noms des oiseaux et leurs valeurs au popup_text pour chaque ligne
for (i in 1:nrow(dataframe)) {
  top_birds <- sort(unlist(dataframe[i, -c(ncol(dataframe))]), decreasing = TRUE)[1:3]
  top_bird_names <- names(top_birds)
  denombrementCarte$popup_text[i] <- paste0(denombrementCarte$popup_text[i],
                                            top_bird_names[1], ": ", top_birds[1], " - ", traits[which(traits$Nom.latin == top_bird_names[1]), "Niveau.de.spécialisation"], "<br>",
                                            top_bird_names[2], ": ", top_birds[2], " - ", traits[which(traits$Nom.latin == top_bird_names[2]), "Niveau.de.spécialisation"], "<br>",
                                            top_bird_names[3], ": ", top_birds[3], " - ", traits[which(traits$Nom.latin == top_bird_names[3]), "Niveau.de.spécialisation"])
}

pal <- colorNumeric("viridis", domain = denombrementCarte$MOS11)


leaflet(data = denombrementCarte) %>%
  addProviderTiles("CartoDB.Positron") %>%
  addCircles(radius = 300, color = ~pal(MOS11), fillOpacity = 0.2, popup = ~popup_text) %>%
  addLegend("bottomright", pal = pal, values = ~MOS11, title = "MOS11", position = "bottomright") %>%
  addScaleBar(position = "bottomleft")

Grâce à cette carte, nous obtenons le classement (Top 3) des oiseaux les plus observés dans chaque maille de mesure pour l’année 2023. Nous avons également ajouté une information supplémentaire sur chaque oiseau pour mettre en évidence son niveau de spécialisation afin de mieux comprendre de quel type de milieu il a besoin pour vivre et la géolocalisation sur la Gironde.

Nous pouvons voir que le niveau de spécialisation le plus répendu est généraliste car on en retrouve au centre-ville et en périphérie. Egalement, au centre ville, on retrouve des oiseaux de type Bâti et en périphérie loins du centre-ville, on retrouve des oiseaux de type Fôret et Agricole. Proche des points d’eau, on trouve des oiseaux de type Zone humide.

Ainsi, les zones qui combinent à la fois végétation et bâtiments seraient plus susceptibles d’accueillir des oiseaux avec des niveaux de spécialisation variés, ce qui expliquerait l’augmentation du taux de diversité observée dans les zones où se mélangent espaces verts et zones urbanisées.

Il nous semblait intéressant de savoir quels étaient les régimes alimentaires majoritaires principaux en fonction de chaque maille. Nous avons donc créé un graphique qui montre la répartition des régimes alimentaires pour chaque maille.

# changed the unmatchinng latin names to the correct ones to match alimentation
denombrement$latin[denombrement$latin == "Carduelis chloris"] <- "Chloris chloris"
denombrement$latin[denombrement$latin == "Carduelis spinus"] <- "Spinus spinus"
denombrement$latin[denombrement$latin == "Casmerodius albus"] <- "Ardea alba"
denombrement$latin[denombrement$latin == "Carduelis cannabina"] <- "Linaria cannabina"
no_info <- c("Himantopus himantopus", "Tringa ochropus", 
             "Caprimulgus europaeus", "Lanius senator", 
             "Dryocopus martius", "Emberiza calandra")

alimentation <- read.csv("data/birds/traits-statut-IUCN-biodivercite.csv", header = TRUE)
denombrement$regime_alimentaire <- rep(NA, nrow(denombrement))
for (i in 1:nrow(denombrement)) {
  if (denombrement$latin[i] %in% no_info){
    denombrement$regime_alimentaire[i] <- NA
  }
  else {
    denombrement$regime_alimentaire[i] <- 
      alimentation$Régime.alimentaire[which(alimentation$Nom.latin == denombrement$latin[i])]
  }
}
denombrement$regime_alimentaire <- as.factor(denombrement$regime_alimentaire)

plot_data = function (data, title) {
    ggplot(data, aes(x="", y=sum, fill=regime_alimentaire)) +
    geom_bar(stat="identity", width=0.1) +
    coord_polar("y", start=0) +
    ggtitle(paste("Station: ", as.character(title))) +
    theme_void()
}

cite <- cite %>%
  select(code_site, Nom_lieu)

#On join les deux tables cite et denombrementCarte

denombrement <- left_join(denombrement, cite, by = c("Code_Maille" = "code_site"))

N <- length(unique(denombrement$Code_Maille))
p <- vector("list", length = N)

for (i in 1:N) {
    data <- denombrement[which(denombrement$Code_Maille == unique(denombrement$Code_Maille)[i]),]
    data <- data %>% group_by(regime_alimentaire) %>% summarise(sum = sum(p, na.rm = TRUE))
    p[[i]] <- plot_data(data, unique(denombrement$Nom_lieu)[i])
}

coordinates <- st_as_sf(LUP, coords = c("X", "Y"), crs = 2154)
coordinates <- st_transform(coordinates, crs = 4326)
coordinates <- coordinates[coordinates$BufferSize == 500,]

# Remove the coordinates that are not in denombrement
for (i in seq_along(coordinates$ID)){
  if (!(coordinates$ID[i] %in% unique(denombrement$Code_Maille))){
    coordinates <- coordinates[-i,]
  }
}

coordinates <- coordinates[order(coordinates$ID, decreasing = TRUE),]

pal <- colorNumeric("viridis", domain = coordinates$MOS11)
leaflet(data = coordinates) %>%
  addProviderTiles("CartoDB.Positron") %>%
  addCircles(radius = 300, color = ~pal(MOS11), 
             fillOpacity = 0.5, group = "pnt") %>%
  addLegend("bottomright", pal = pal, values = coordinates$MOS11, title = "MOS11") %>%
  addScaleBar(position = "bottomleft") %>% 
  addPopupGraphs(p, width = 200, height = 200, group = "pnt")

Voici à quoi ressemble la carte interactive qui montre les régimes alimentaires majoritaires principaux en fonction de chaque maille. Nous pouvons voir qu’en général, le régime alimentaire dominant est le régime alimentaire mixte, que cela soit au centre de Bordeaux ou en périphérie. Il semble donc que le régime alimentaire de l’oiseau ne soit pas véritablement impacté par l’artificialisation des sols. Essayons maintenant d’étudier d’autre caratéristiques afin d’essayer de trouver des raisons à ce pic de diversité.

denombrement$Nidification <- rep(NA, nrow(denombrement))
for (i in 1:nrow(denombrement)) {
  if (denombrement$latin[i] %in% no_info){
    denombrement$Nidification[i] <- NA
  }
  else {
    denombrement$Nidification[i] <- 
      alimentation$Nidification[which(alimentation$Nom.latin == denombrement$latin[i])]
  }
}
denombrement$Nidification <- as.factor(denombrement$Nidification)

plot_data = function (data, title) {
    ggplot(data, aes(x="", y=sum, fill=Nidification)) +
    geom_bar(stat="identity", width=0.1) +
    coord_polar("y", start=0) +
    ggtitle(paste("Station: ", as.character(title))) +
    theme_void()
}

#On join les deux tables cite et denombrementCarte

N <- length(unique(denombrement$Code_Maille))
p <- vector("list", length = N)

for (i in 1:N) {
    data <- denombrement[which(denombrement$Code_Maille == unique(denombrement$Code_Maille)[i]),]
    data <- data %>% group_by(Nidification) %>% summarise(sum = sum(p, na.rm = TRUE))
    p[[i]] <- plot_data(data, unique(denombrement$Nom_lieu)[i])
}

coordinates <- st_as_sf(LUP, coords = c("X", "Y"), crs = 2154)
coordinates <- st_transform(coordinates, crs = 4326)
coordinates <- coordinates[coordinates$BufferSize == 500,]

# Remove the coordinates that are not in denombrement
for (i in seq_along(coordinates$ID)){
  if (!(coordinates$ID[i] %in% unique(denombrement$Code_Maille))){
    coordinates <- coordinates[-i,]
  }
}

coordinates <- coordinates[order(coordinates$ID, decreasing = TRUE),]

pal <- colorNumeric("viridis", domain = coordinates$MOS11)
leaflet(data = coordinates) %>%
  addProviderTiles("CartoDB.Positron") %>%
  addCircles(radius = 300, color = ~pal(MOS11), 
             fillOpacity = 0.5, group = "pnt2") %>%
  addLegend("bottomright", pal = pal, values = coordinates$MOS11, title = "MOS11") %>%
  addScaleBar(position = "bottomleft") %>% 
  addPopupGraphs(p, width = 200, height = 200, group = "pnt2")

Cette carte illustre la répartition des types de nidification en fonction des zones géographiques. Il est observé que dans les zones centrales, la majorité des nids sont situés dans des cavités, ce qui peut être attribué à la densité élevée de bâtiments et à la rareté de la végétation en ville. Le mode de nidification au sol est le moins courant dans ces zones, probablement en raison de la faible probabilité de survie des oiseaux dans un environnement urbain avec un nid au sol.

En périphérie, les modes de nidification semblent plus diversifiés, avec une prédominance de la nidification en buisson. La nidification dans les arbres est également très répandue, et on retrouve aussi la nidification en cavité. Le fait de ne pas être situé directement au centre-ville semble offrir plus de possibilités de nidification, ce qui pourrait expliquer une plus grande diversité d’espèces si on s’éloigne légèrement du centre ville, grâce à une combinaison de bâtiments et de végétation offrant plus de choix pour la nidification.

Pour aller plus loin

Cette section est dédiée à des analyses plus poussées qui pourraient être réalisées pour mieux comprendre les données et les relations entre les différentes variables. Vous trouverez un Parallel Coordinates Plot ainsi qu’un sun burst plot qui illustrent les caractéristiques des différentes espèces d’oiseaux.

Voici, ci-dessous le Parallel Coordinates Plot intéractif. Vous pouvez cliquer sur les différentes espèces pour obtenir plus d’informations sur chacune d’elles.

# --- Load data ---

birds_info <- read.csv("data/birds/traits-statut-IUCN-biodivercite.csv", header = TRUE)
birds_info <- birds_info[, c(
  "Nom.latin",
  "Niveau.de.spécialisation",
  "Régime.alimentaire",
  "Technique.d.alimentation",
  "Nidification",
  "Période.de.migration"
)]

# --- Parcoords data preparation ---

unique_level <- unique(birds_info[, "Niveau.de.spécialisation"])
unique_regime <- unique(birds_info[, "Régime.alimentaire"])
unique_technique <- unique(birds_info[, "Technique.d.alimentation"])
unique_nidi <- unique(birds_info[, "Nidification"])
unique_migration <- unique(birds_info[, "Période.de.migration"])

plot_ly(data.frame(), type = "parcoords", line = list(color = "blue"), height = 950,
  dimensions = list(
    list(
      label = "Espèces",
      range = c(0, length(birds_info[, "Nom.latin"]) + 1),
      tickvals = 1:length(birds_info[, "Nom.latin"]),
      ticktext = birds_info[, "Nom.latin"],
      values = 1:length(birds_info[, "Nom.latin"])
    ),
    list(
      label = "Technique d'alimentation",
      range = c(0, length(unique_technique) + 1),
      tickvals = as.numeric(factor(unique_technique)),
      ticktext = unique_technique,
      values = as.numeric(factor(birds_info[, "Technique.d.alimentation"]))
    ),
    list(
      label = "Nidification",
      range = c(0, length(unique_nidi) + 1),
      tickvals = as.numeric(factor(unique_nidi)),
      ticktext = unique_nidi,
      values = as.numeric(factor(birds_info[, "Nidification"]))
    ),
    list(
      label = "Niveau de spécialisation",
      range = c(0, length(unique_level) + 1),
      tickvals = as.numeric(factor(unique_level)),
      ticktext = unique_level,
      values = as.numeric(factor(birds_info[, "Niveau.de.spécialisation"]))
    ),
    list(
      label = "Période de migration",
      range = c(0, length(unique_migration) + 1),
      tickvals = as.numeric(factor(unique_migration)),
      ticktext = unique_migration,
      values = as.numeric(factor(birds_info[, "Période.de.migration"]))
    ),
    list(
      label = "Régime alimentaire",
      range = c(0, length(unique_regime) + 1),
      tickvals = as.numeric(factor(unique_regime)),
      ticktext = unique_regime,
      values = as.numeric(factor(birds_info[, "Régime.alimentaire"]))
    )
  )
) %>% layout(
  title = "Caractéristiques des différentes espèces d'oiseaux",
  margin = list(l = 140, r = 55, b = 0)
)

Exemple d’utilisation :

  • Nous voulons savoir le régime alimentaire des oiseaux qui migrent. Pour cela, il suffit de cliquer au niveau de “migrateur tardif” et de cliquer sur “Végétarien”, “Mixte” ou “carnivore” pour obtenir les espèces d’oiseaux qui correspondent à ces critères. Ceci est très utile lorsqu’on veut comparer le nombre d’oiseau selon les caractéristiques choisies ou même simplement rechercher l’espèce qui correspond à certains critères que l’on veut étudier. Pour finir l’exemple, si on clique au niveau de “Migrateur tardif”, on remarque qu’aucun oiseau n’est végétarien. De plus, on peut affiner notre sélection pour voir quelles espèces d’oiseaux sont des migrateurs tardifs et font leur nid dans les buissons. On clique ainsi sur buisson et on voit que l’espèce “Lanius collurio” correspond à ces critères. C’est une espèce carnivore qui migre tardivement et fait son nid dans les buissons qui a un niveau de spécialisation agricole et qui s’alimente en vol.
Voici une image de la pie-grièche écorcheur (Lanius collurio), wikipedia
Voici une image de la pie-grièche écorcheur (Lanius collurio), wikipedia
# --- Load data ---

LUP <- read.csv("data/birds/LandUsePer_BM_2023_cartoISea.csv", header = TRUE)
LUP <- LUP[, c(c("ID", "BufferSize"), paste0("MOS", 1:14))]

birds_obs <- read.csv("data/birds/Oiseaux_up_to_2023.csv", header = TRUE, sep = "\t")
birds_obs <- birds_obs[, c(c("Code_Maille", "Date", "Nom_Taxon_Cite", "Denombrement_min"))]
birds_obs <- birds_obs %>%
  rename(Year = Date, ID = Code_Maille, Latin = Nom_Taxon_Cite)

birds_obs[, "Year"] <- substr(birds_obs[, "Year"], start = 1, stop = 4)
birds_obs[, "Latin"] <- sapply(strsplit(birds_obs[, "Latin"], split = " | ", fixed = TRUE), function(x) x[1])

birds_obs <- birds_obs %>%
  group_by(ID, Year, Latin) %>%
  summarise(Sum = sum(Denombrement_min), .groups = "drop")

LUP_birds_obs <- merge(LUP, birds_obs, by = "ID")

# --- Sunburst data preparation ---

unique_year <- unique(LUP_birds_obs[, "Year"])
unique_year <- unique_year[order(unique_year)]

ids <- c("Année", unique_year)
for (year in unique_year) {
  ids <- c(ids, paste0(year, paste0(" - MOS", 1:14)))
}

for (year in unique_year) {
  for (mos in paste0("MOS", 1:14)) {
    for (specie in birds_info[, "Nom.latin"]) {
      ids <- c(ids, paste0(year, paste0(paste0(" - ", mos), paste0(" - ", specie))))
    }
  }
}

labels <- c("Année", unique_year, rep(paste0("MOS", 1:14), times = length(unique_year)))
labels <- c(labels, rep(birds_info[, "Nom.latin"], times = 14 * length(unique_year)))

parents <- c("", rep("Année", times = length(unique_year)), rep(unique_year, each = 14))
for (year in unique_year) {
  parents <- c(parents, paste0(year, rep(paste0(" - MOS", 1:14), each = length(birds_info[, "Nom.latin"]))))
}

values <- c(c(length(unique_year) * 14000, rep(14000, times = length(unique_year))), rep(1000, times = length(unique_year) * 14))
for (year in unique_year) {
  for (mos in paste0("MOS", 1:14)) {
    for (specie in birds_info[, "Nom.latin"]) {
      tmp <- LUP_birds_obs[LUP_birds_obs["Year"] == year & LUP_birds_obs["Latin"] == specie & LUP_birds_obs["BufferSize"] == 500, ]
      values <- c(values, sum(tmp[mos] * tmp["Sum"]))
    }
    tail_values <- values[(1 + length(values) - length(birds_info[, "Nom.latin"])):length(values)]
    values[(1 + length(values) - length(birds_info[, "Nom.latin"])):length(values)] <- tail_values / sum(tail_values) * 1000
  }
}

is_nan_values <- !is.na(values) & values != 0
ids <- ids[is_nan_values]
labels <- labels[is_nan_values]
parents <- parents[is_nan_values]
values <- values[is_nan_values]

# --- Sunburst display ---

plot_ly(
  ids = ids,
  labels = labels,
  parents = parents,
  values = values,
  type = "sunburst",
  branchvalues = "total",
  maxdepth = 2,
  insidetextorientation = "radial",
  hoverinfo = "label+percent entry",
  height = 800
) %>% layout(
  title = list(
    text = "Proportion des espèces d'oiseaux les plus couramment observées<br>en fonction de l'année et du MOS",
    y = 1.1
  ),
  margin = list(t = 100)
)

Conclusion

Après avoir mené une étude approfondie sur la diversité des oiseaux à Bordeaux et sa périphérie, nous avons pu faire plusieurs découvertes intéressantes en utilisant différentes mesures de diversité telles que la richesse spécifique, l’indice de Shannon et l’indice de Simpson.

Tout d’abord, nous avons découvert que la diversité des espèces d’oiseaux est étroitement liée au niveau d’artificialisation des sols, mesuré par la variable MOS11. En effet, nous avons constaté que la diversité est plus élevée dans les zones où se mélangent espaces verts et zones urbanisées. Cette observation suggère que les zones urbaines qui préservent des espaces verts et des habitats naturels sont plus susceptibles d’accueillir une grande diversité d’espèces d’oiseaux.

Ensuite, nous avons étudié la relation entre la diversité des espèces d’oiseaux et la distance au centre-ville. Nous avons constaté que la diversité est plus grande lorsque la maille se trouve à environ 9 km du centre-ville. Cette tendance s’explique en partie par le fait que les zones situées à cette distance du centre-ville sont souvent des zones de transition entre les espaces urbains et les espaces ruraux, offrant ainsi une variété d’habitats pour les oiseaux.

Par la suite, nous avons essayé de trouver des liens entre la diversité des espèces d’oiseaux et d’autres caractéristiques telles que les régimes alimentaires, les niveaux de spécialisation et les modes de nidification.

Pour les niveaux de spécialisation, nous avons observé que les oiseaux de type Bâti sont plus répandus dans les zones urbaines, tandis que les oiseaux de type Forêt et Agricole sont plus fréquents en périphérie. Il y aussi de nombreuses espèces de type Zone humide près des points d’eau. Il y a de nombreuses espèces généralistes au centre-ville et en périphérie. Ces observations suggèrent que la diversité des espèces est influencée par les caractéristiques des habitats.

Nous avons également étudié les régimes alimentaires des oiseaux et avons constaté que le régime alimentaire de l’oiseau ne semble pas être impacté par l’artificialisation des sols. Cette observation suggère que les oiseaux sont capables de s’adapter à leur environnement et de trouver de la nourriture même dans les zones urbaines.

Enfin, nous avons étudié les modes de nidification des oiseaux et avons constaté que les zones qui combinent à la fois végétation et bâtiments sont plus susceptibles d’accueillir des oiseaux avec des modes de nidification variés. Par exemple, les zones centrales sont propices à la nidification en cavité en raison de la densité élevée de bâtiments, tandis que les zones périphériques offrent plus de possibilités de nidification en buisson et dans les arbres.
Cette observation souligne l’importance de préserver et de restaurer les habitats naturels dans les zones urbaines pour maintenir un niveau maximal de diversité des espèces d’oiseaux.

En conclusion, notre étude a permis de mettre en évidence l’importance de préserver et de restaurer les habitats naturels dans les zones urbaines pour maintenir la biodiversité des oiseaux. Nous avons constaté que les zones de transition entre les espaces urbains et ruraux sont des zones clés pour la diversité des espèces d’oiseaux. Nous avons également observé que les oiseaux sont capables de s’adapter à leur environnement et de trouver de la nourriture même dans les zones urbaines. Ces résultats soulignent l’importance de prendre en compte la biodiversité dans les politiques d’aménagement urbain et de préserver les habitats naturels pour maintenir la diversité des espèces d’oiseaux. En utilisant différentes mesures de diversité, nous avons pu confirmer ces résultats et renforcer la validité de notre étude.

mos_table <- read.csv("data/birds/themes_mos_gir.txt", header = TRUE, sep = "\t")
mos_table <- mos_table[, c("ID", "MOS")]
mos_table["ID"] <- paste0("MOS", mos_table[, "ID"])

mos_table
LS0tDQp0aXRsZTogIlByb2pldCBzdGF0IHBvdXIgZG9ubsOpZXMgZW52aXJvbm5lbWVudGFsZXMiDQphdXRob3I6ICJBbGV4YW5kcmUgTGV5cywgQmFwdGlzdGUgR2VyYm91aW4sIEhhbWFkIFRyaWEsIExvdWlzIERlbGlnbmFjLCBUaMOpbyBMYXZhbmRpZXIiDQpkYXRlOiAiYHIgZm9ybWF0KFN5cy5EYXRlKCksICclZCAlQiwgJVknKWAiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIHRoZW1lOiB1bml0ZWQNCiAgICBoaWdobGlnaHQ6IHRhbmdvDQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgdG9jX2RlcHRoOiAyDQogICMgcGRmX2RvY3VtZW50Og0KICAjICAgdG9jOiB0cnVlDQogICMgICB0b2NfZGVwdGg6IDINCiAgIyAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQ0KICAjICAgZGZfcHJpbnQ6IGthYmxlDQogICMgICBoaWdobGlnaHQ6IHRhbmdvDQotLS0NCg0KPHN0eWxlPg0KICAudG9jaWZ5LWV4dGVuZC1wYWdlIHsNCiAgICBkaXNwbGF5OiBub25lOw0KICB9DQo8L3N0eWxlPg0KDQojIEludHJvZHVjdGlvbg0KDQoNCkRhbnMgbGUgY2FkcmUgZGUgbm90cmUgcHJvamV0IGRlIHN0YXRpc3RpcXVlcywgbm91cyB0cmF2YWlsbGVyb25zIHN1ciB1biBqZXUgZGUgZG9ubsOpZXMgZW52aXJvbm5lbWVudGFsZXMuDQpDZSBqZXUgZGUgZG9ubsOpZXMgZXN0IGNvbXBvc8OpIGRlIHBsdXNpZXVycyBmaWNoaWVycyBxdWkgY29udGllbm5lbnQgZGVzIGluZm9ybWF0aW9ucyBzdXIgbGVzIG9pc2VhdXgsIGxlcyBzdGF0aW9ucyBkZSBtZXN1cmUsIGxlcyBjYXJhY3TDqXJpc3RpcXVlcyBkZXMgb2lzZWF1eCwgbGV1cnMgcsOpZ2ltZXMgYWxpbWVudGFpcmVzIGV0IGxhIGJpb2RpdmVyc2l0w6kuDQoNCkNlIHJhcHBvcnQgYSBwb3VyIG9iamVjdGlmIGRlIHByw6lzZW50ZXIgbGVzIGRpZmbDqXJlbnRlcyBhbmFseXNlcyBxdWUgbm91cyBhdm9ucyByw6lhbGlzw6llcyBzdXIgY2VzIGRvbm7DqWVzLg0KSWwgZXN0IGNvbXBvc8OpIGRlIHRyb2lzIHBhcnRpZXMgcHJpbmNpcGFsZXMgZGFucyBsZXNxdWVsbGVzIG5vdXMgZXhwbG9yb25zIGxlcyByZWxhdGlvbnMgZW50cmUgbGEgZGl2ZXJzaXTDqSBkZXMgZXNww6hjZXMgZCdvaXNlYXV4LCBsJ2FydGlmaWNpYWxpc2F0aW9uIGRlcyBzb2xzIGV0IGxhIGRpc3RhbmNlIGF2ZWMgbGUgY2VudHJlLXZpbGxlIGRlIEJvcmRlYXV4Lg0KTm91cyBhdm9ucyDDqWdhbGVtZW50IMOpdHVkacOpIGxlcyByw6lnaW1lcyBhbGltZW50YWlyZXMgZGVzIG9pc2VhdXggZXQgbGVzIG1vZGVzIGRlIG5pZGlmaWNhdGlvbiBlbiBmb25jdGlvbiBkZSBjZXJ0YWluZXMgem9uZXMgZ8Opb2dyYXBoaXF1ZXMuDQoNClZvdXMgdHJvdXZlcmV6IGRlcyBjYXJ0ZXMsIGRlcyBncmFwaGlxdWVzLCBkZXMgdGFibGVhdXgsIHVuIHNhbmtpZSBwbG90IGFpbnNpIHF1J3VuIHN1bmJ1cnN0IHBsb3QgcXVpIG5vdXMgcGVybWV0dHJvbnQgZGUgZMOpY291dnJpciBsYSBtZXN1cmUgZGUgbGEgYmlvZGl2ZXJzaXTDqS4NCg0KTCdlbnNlbWJsZSBkZSBjZXMgZG9ubsOpZXMgc29udCB0aXLDqWVzIGR1IHRyYXZhaWwgZGVzIG1lbWJyZXMgZGUgbCdJTlJBRSB1bml0w6kgQmlvR2VDbyBldCBkdSBidXJlYXUgZGUgdMOpbMOpZGV0ZWN0aW9uIEktc2VhLg0KDQpWb3VzIHRyb3V2ZXJleiBkZSBub21icmV1eCByw6lzdWx0YXRzIGNvbW1lIHBsdXNpZXVycyBjb3VyYmVzIGRlIGRpdmVyc2l0w6kgcsOpdsOpbGFudCBsYSBiYWlzc2Ugc2lnbmlmaWNhdGl2ZSBkZSBkaXZlcnNpdMOpIGRhbnMgbGVzIGxpZXV4IGxlcyBwbHVzIGFydGlmaWNpYWxpc8Opcy4NClZvdXMgdHJvdXZlcmV6IMOpZ2FsZW1lbnQgbCdlbnRpw6hyZXTDqSBkZSBub3RyZSBjaGVtaW5lbWVudCBwb3VyIGFycml2ZXIgw6Agbm9zIHLDqXN1bHRhdHMgc3RhdGlzdGlxdWVzLCBub3RhbW1lbnQgY29uY2VybmFudCBsYSBkaXN0cmlidXRpb24gZGVzIGVzcMOoY2VzIGQnb2lzZWF1eCBvYnNlcnbDqWVzIGVuIEdpcm9uZGUsIG1haXMgYXVzc2kgZGVzIHN0YXRpc3RpcXVlcyBtdWx0aXZhcmnDqWVzIGV0IGRlc2NyaXB0aXZlcy4NCg0KTm91cyB2b3VzIGludml0b25zIMOgIGTDqWNvdXZyaXIgbCdlbnNlbWJsZSBkZSBub3MgYW5hbHlzZXMgZXQgw6AgZXhwbG9yZXIgbGVzIGRpZmbDqXJlbnRlcyB2aXN1YWxpc2F0aW9ucyBxdWUgbm91cyBhdm9ucyByw6lhbGlzw6llcyBwb3VyIG1pZXV4IGNvbXByZW5kcmUgbGVzIHJlbGF0aW9ucyBlbnRyZSBsZXMgZGlmZsOpcmVudGVzIHZhcmlhYmxlcyBkZSBub3RyZSBqZXUgZGUgZG9ubsOpZXMuDQpUb3V0ZXMgbm9zIHZpc3VhbGlzYXRpb25zIHNvbnQgaW50ZXJhY3RpdmVzIGV0IHZvdXMgcGVybWV0dGVudCBkZSB6b29tZXIsIGRlIGTDqXBsYWNlciBldCBkZSBjbGlxdWVyIHN1ciBsZXMgZGlmZsOpcmVudHMgw6lsw6ltZW50cyBwb3VyIG9idGVuaXIgcGx1cyBkJ2luZm9ybWF0aW9ucy4NCkNlbGEgdm91cyBwZXJtZXR0cmEgZCdhdm9pciB1bmUgZXhww6lyaWVuY2UgcGx1cyBpbW1lcnNpdmUgZXQgdm91cyBwZXJtZXR0cmEgZGUgY3LDqWVyIHZvcyBwcm9wcmVzIGFuYWx5c2VzLCBlbiBwYXJhbGzDqGxlIMOgIGNlbGxlcyByw6lhbGlzw6llcyBwYXIgbm9zIHNvaW5zLg0KDQpgYGB7ciBzZXR1cCwgbWVzc2FnZT1GQUxTRSwgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgUGFja2FnZXMgZGUgZ2VzdGlvbiBkZXMgZG9ubsOpZXMNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShzZikNCg0KIyBQYWNrYWdlcyBwb3VyIHZpc3VhbGlzYXRpb24gZGVzIGRvbm7DqWVzDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGdnc3BhdGlhbCkNCmxpYnJhcnkoa2FibGVFeHRyYSkNCmxpYnJhcnkobGF0dGljZSkNCmxpYnJhcnkocGxvdGx5KQ0KDQojIFBhY2thZ2VzIHBvdXIgdmlzdWFsaXNhdGlvbiBkZSBjYXJ0ZXMgaW50w6lyYWN0aXZlcw0KbGlicmFyeShsZWFmbGV0KQ0KbGlicmFyeShsZWFmcG9wKQ0KbGlicmFyeShsZWFmbGV0LmV4dHJhcykNCg0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KG91dC53aWR0aCA9ICIxMDAlIiwgZWNobyA9IFRSVUUpDQpgYGANCg0KIyBFeHBsb3JhdGlvbiBkZXMgZG9ubsOpZXMNCg0KUG91ciBjb21tZW5jZXIsIG5vdXMgY2hhcmdlb25zIGxlcyBkb25uw6llcyBldCBub3VzIGxlcyBleHBsb3JvbnMgcG91ciBtaWV1eCBjb21wcmVuZHJlIGxldXIgc3RydWN0dXJlLg0KRGFucyB1biBwcmVtaWVyIHRlbXBzLCBub3VzIGFsbG9ucyBham91dGVyIHVuZSBjb2xvbm5lIMOgIG5vdHJlIERhdGFGcmFtZSBxdWkgY29udGllbnQgbGVzIG5vbXMgbGF0aW5zIGRlcyBvaXNlYXV4IGFmaW4gZGUgZmFjaWxsaXRlciBsZXMgYW5hbHlzZXMgcGFyIGxhIHN1aXRlLg0KYGBge3J9DQpvaXNlYXV4IDwtIHJlYWQuY3N2KCJkYXRhL2JpcmRzL09pc2VhdXhfdXBfdG9fMjAyMy5jc3YiLCBoZWFkZXIgPSBUUlVFLCBzZXAgPSAiXHQiKQ0KIyBDUsOJRVIgVU5FIE5PVVZFTExFIENPTE9OTkUgREFOUyBMRSBEQVRBRlJBTUUgT0lTRUFVWCBRVUkgQ09OVElFTlQgTEUgTk9NIExBVElOIERFIEwnT0lTRUFVDQpteV9zcGxpdCA8LSBmdW5jdGlvbihhcnJheSwgc3RyID0gIiBcXHwgIikgew0KICBvdXQgPC0gcmVwKE5BLCBsZW5ndGgoYXJyYXkpKQ0KICBmb3IgKGkgaW4gMTpsZW5ndGgoYXJyYXkpKSB7DQogICAgb3V0W2ldIDwtIHVubGlzdChzdHJzcGxpdChhcnJheVtpXSwgc3RyKSlbMV0NCiAgfQ0KICByZXR1cm4ob3V0KQ0KfQ0KDQpvbmx5X2xhdGluIDwtIG15X3NwbGl0KGFzLnZlY3RvcihvaXNlYXV4JE5vbV9UYXhvbl9DaXRlKSkNCg0Kb2lzZWF1eCRsYXRpbiA8LSBvbmx5X2xhdGluDQpvaXNlYXV4JGFubmVlIDwtIGFzLm51bWVyaWMoc3Vic3RyKG9pc2VhdXgkRGF0ZSwgMSwgNCkpDQpgYGANCg0KDQpQYXIgbGEgc3VpdGUsIG5vdXMgYWxsb25zIGV4cGxvcmVyIGxlcyBkb25uw6llcyBwb3VyIG1pZXV4IGNvbXByZW5kcmUgbGEgZGlzdHJpYnV0aW9uIGRlcyBlc3DDqGNlcyBkJ29pc2VhdXggb2JzZXJ2w6llcy4NClZvaWNpIHVuIHRhYmxlYXUgcXVpIG1vbnRyZSBsZXMgMTAgZXNww6hjZXMgZCdvaXNlYXV4IGxlcyBwbHVzIGZyw6lxdWVtbWVudCBvYnNlcnbDqWVzIGRhbnMgbCdlbnNlbWJsZSBkZXMgZG9ubsOpZXMuDQpgYGB7cn0NCiMgTEVTIEVTUMOIQ0VTIEQnT0lTRUFVWCBMRVMgUExVUyBGUsOJUVVFTlRFUyBPQlNFUlbDiUVTIERBTlMgTCdFTlNFTUJMRSBERVMgRE9OTsOJRVMNCmFzLmRhdGEuZnJhbWUoc29ydCh0YWJsZShvaXNlYXV4JGxhdGluKSwgZGVjcmVhc2luZyA9IFRSVUUpWzE6MTBdKQ0KYGBgDQoNCk5vdXMgYWxsb25zIG1haW50ZW5hbnQgZXhwbG9yZXIgbGEgZnLDqXF1ZW5jZSBkZXMgZXNww6hjZXMgZCdvaXNlYXV4IG9ic2VydsOpZXMgZGFucyBsJ2Vuc2VtYmxlIGRlcyBkb25uw6llcyBwYXIgYW5uw6llLg0KVm9pY2ksIHBhciBvcmRyZSBhbHBoYWLDqXRpcXVlLCBsZSB0YWJsZWF1IG1ldHRhbnQgZW4gw6l2aWRlbmNlIGNldHRlIGZyw6lxdWVuY2UuDQoNCmBgYHtyfQ0KIyBGUsOJUVVFTkNFIERFUyBFU1DDiENFUyBEJ09JU0VBVVggT0JTRVJWw4lFUyBEQU5TIEwnRU5TRU1CTEUgREVTIERPTk7DiUVTIFBBUiBBTk7DiUUNCkFubmVlIDwtIG15X3NwbGl0KGFzLnZlY3RvcihvaXNlYXV4JERhdGUpLCBzdHIgPSAiLSIpDQpvaXNlYXV4JEFubmVlIDwtIGFzLmZhY3RvcihBbm5lZSkNCmFzLmRhdGEuZnJhbWUubWF0cml4KHRhYmxlKG9pc2VhdXgkbGF0aW4sIG9pc2VhdXgkQW5uZWUpKQ0KYGBgDQoNCiMjIyBNZXN1cmUgZGUgbGEgZGl2ZXJzaXTDqSB7LnRhYnNldH0NCg0KRGFucyBjZXR0ZSBwYXJ0aWUsIG5vdXMgYWxsb25zIGV4cGxvcmVyIGxhIG1lc3VyZSBkZSBsYSBkaXZlcnNpdMOpIMOgIMOgIGwnYWlkZSBkZSBwbHVzaWV1cnMgZW50cm9waWVzLg0KTm91cyBub3VzIGludMOpcmVzc2Vyb25zIHVuaXF1ZW1lbnQgYXUgTU9TMTEsIGMnZXN0IMOgIGRpcmUgbGVzIHN1cmZhY2VzIGFydGlmaWNpYWxpc8OpZXMuIE9uIHByZW5kIGNvbW1lIGJ1ZmZlciBzaXplIDUwMG0uDQoNCkRhbnMgdW4gcHJlbWllciB0ZW1wcywgbm91cyBhbGxvbnMgdXRpbGlzZXIgbGEgcHJvcG9ydGlvbiBk4oCZZXNww6hjZXMgZGlmZsOpcmVudGVzIG9ic2VydsOpZXMgZGFucyB1bmUgc3RhdGlvbiBwb3VyIG1lc3VyZXIgbGEgZGl2ZXJzaXTDqS4gRGFucyB1biBkZXV4acOobWUgdGVtcHMsIG5vdXMgYWxsb25zIHV0aWxpc2VyIGzigJllbnRyb3BpZSBkZSBTaGFubm9uIGV0IGVuZmluIGwnaW5kaWNlIGRlIFNpbXBzb24uDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyMgQW5hbHlzZSBkZSBkaXZlcnNpdMOpIHBhciByYXBwb3J0IMOgIE1PUzExIGV0IHBhciBhbm7DqWUNCg0KZGVub21icmVtZW50IDwtIG9pc2VhdXggJT4lDQogIGdyb3VwX2J5KENvZGVfTWFpbGxlLCBhbm5lZSwgbGF0aW4pICU+JQ0KICBzdW1tYXJpc2Uoc3VtID0gc3VtKERlbm9tYnJlbWVudF9taW4sIG5hLnJtID0gVFJVRSksIC5ncm91cHMgPSAiZHJvcCIpICU+JQ0KICBhcnJhbmdlKGRlc2MoQ29kZV9NYWlsbGUpKQ0KDQpkZW5vbWJyZW1lbnQkcCA8LSByZXAoTkEsIG5yb3coZGVub21icmVtZW50KSkNCmZvciAoaSBpbiAxOm5yb3coZGVub21icmVtZW50KSkgew0KICBudW1lcmF0b3IgPC0gZGVub21icmVtZW50JHN1bVtpXQ0KICBkZW5vbWluYXRvciA8LQ0KICAgIHN1bShkZW5vbWJyZW1lbnQkc3VtW3doaWNoKGRlbm9tYnJlbWVudCRDb2RlX01haWxsZSA9PSBkZW5vbWJyZW1lbnQkQ29kZV9NYWlsbGVbaV0NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAmIGRlbm9tYnJlbWVudCRhbm5lZSA9PSBkZW5vbWJyZW1lbnQkYW5uZWVbaV0pXSkNCiAgZGVub21icmVtZW50JHBbaV0gPC0gbnVtZXJhdG9yIC8gZGVub21pbmF0b3INCn0NCg0KaW5kZXggPC0gZGVub21icmVtZW50ICU+JQ0KICBncm91cF9ieShDb2RlX01haWxsZSwgYW5uZWUgPSBmYWN0b3IoYW5uZWUpKSAlPiUNCiAgc3VtbWFyaXNlKEQxID0gc3VtKHAgPiAwLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgRDIgPSBleHAoLXN1bShwICogbG9nKHApKSksDQogICAgICAgICAgICBEMyA9IDEgLyBzdW0ocF4yKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lDQogIGFycmFuZ2UoZGVzYyhDb2RlX01haWxsZSkpDQoNCkxVUCA8LSByZWFkLmNzdigiZGF0YS9iaXJkcy9MYW5kVXNlUGVyX0JNXzIwMjNfY2FydG9JU2VhLmNzdiIsIGhlYWRlciA9IFRSVUUpDQppbmRleCRNT1MxMSA8LSByZXAoTkEsIG5yb3coaW5kZXgpKQ0KZm9yIChpIGluIDE6bnJvdyhpbmRleCkpIHsNCiAgaW5kZXgkTU9TMTFbaV0gPC0gTFVQJE1PUzExW3doaWNoKGluZGV4JENvZGVfTWFpbGxlW2ldID09IExVUCRJRCAmIExVUCRCdWZmZXJTaXplID09IDUwMCldDQp9DQpgYGANCg0KIyMjIyBQcm9wb3J0aW9uIGQnZXNww6hjZXMNCg0KVm9pY2kgbGUgZ3JhcGhpcXVlIHF1aSBtb250cmUgbGEgcmVsYXRpb24gZW50cmUgbGEgZGl2ZXJzaXTDqSBldCBNT1MxMSBwb3VyIGNoYXF1ZSBhbm7DqWUgZXhwbGlxdcOpZSBwYXIgbGEgcHJvcG9ydGlvbiBkJ2VzcMOoY2VzLg0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGVycm9yPUZBTFNFfQ0KZ2dwbG90KGluZGV4LCBhZXMoeCA9IE1PUzExLCB5ID0gRDEsIGNvbG9yID0gYXMuZmFjdG9yKGFubmVlKSkpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMikgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAiYXV0byIsIHNlID0gVFJVRSwgY29sb3IgPSAiYmxhY2siLCBhbHBoYSA9IDAuMikgKw0KICBsYWJzKHRpdGxlID0gIlByb3BvcnRpb24gZOKAmWVzcMOoY2VzIGVuIGZvbmN0aW9uIGRlIE1PUzExIiwNCiAgICAgICB4ID0gIk1PUzExIiwNCiAgICAgICB5ID0gIlByb3BvcnRpb24gZCdlc3DDqGNlcyIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgbGFicyhjb2xvdXIgPSAiQW5uw6llIikgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikNCmBgYA0KDQojIyMjIEluZGljZSBkZSBTaGFub24NCg0KQ2VjaSBlc3QgbGUgZ3JhcGhpcXVlIHF1aSBtb250cmUgbGEgcmVsYXRpb24gZW50cmUgbGEgZGl2ZXJzaXTDqSBldCBNT1MxMSBwb3VyIGNoYXF1ZSBhbm7DqWUgZXhwbGlxdcOpZSBwYXIgbCdlbnRyb3BpZSBkZSBTaGFubm9uLg0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGVycm9yPUZBTFNFfQ0KZ2dwbG90KGluZGV4LCBhZXMoeCA9IE1PUzExLCB5ID0gRDIsIGNvbG9yID0gYXMuZmFjdG9yKGFubmVlKSkpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMikgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAiYXV0byIsIHNlID0gVFJVRSwgY29sb3IgPSAiYmxhY2siLCBhbHBoYSA9IDAuMikgKw0KICBsYWJzKHRpdGxlID0gIkluZGljZSBkZSBTaGFub24gZW4gZm9uY3Rpb24gZGUgTU9TMTEiLA0KICAgICAgIHggPSAiTU9TMTEiLA0KICAgICAgIHkgPSAiSW5kaWNlIGRlIFNoYW5vbiIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgbGFicyhjb2xvdXIgPSAiQW5uw6llIikgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikNCmBgYA0KDQojIyMjIEluZGljZSBkZSBTaW1wc29uDQoNCkNlY2kgZXN0IGxlIGdyYXBoaXF1ZSBxdWkgbW9udHJlIGxhIHJlbGF0aW9uIGVudHJlIGxhIGRpdmVyc2l0w6kgZXQgTU9TMTEgcG91ciBjaGFxdWUgYW5uw6llIGV4cGxpcXXDqWUgcGFyIGwnaW5kaWNlIGRlIFNpbXBzb24uDQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZXJyb3I9RkFMU0V9DQpnZ3Bsb3QoaW5kZXgsIGFlcyh4ID0gTU9TMTEsIHkgPSBEMywgY29sb3IgPSBhcy5mYWN0b3IoYW5uZWUpKSkgKw0KICBnZW9tX3BvaW50KHNpemUgPSAyKSArDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJhdXRvIiwgc2UgPSBUUlVFLCBjb2xvciA9ICJibGFjayIsIGFscGhhID0gMC4yKSArDQogIGxhYnModGl0bGUgPSAiSW5kaWNlIGRlIFNpbXBzb24gZW4gZm9uY3Rpb24gZGUgTU9TMTEiLA0KICAgICAgIHggPSAiTU9TMTEiLA0KICAgICAgIHkgPSAiSW5kaWNlIGRlIFNpbXBzb24iKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIGxhYnMoY29sb3VyID0gIkFubsOpZSIpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpDQpgYGANCg0KIyMjDQoNCkxhIHRlbmRhbmNlIGdsb2JhbGUgZXN0IGwnYXVnbWVudGF0aW9uIGRlIGxhIGRpdmVyc2l0w6kgYXUgZMOpYnV0IGRlIGxhIGNvdXJiZSBqdXNxdSfDoCBhdHRlaW5kcmUgdW4gbWF4aW11bSBwdWlzIHVuZSBiYWlzc2UgcXVhbmQgbGUgTU9TMTEgYXVnbWVudGUgZGF2YW50YWdlLiBDJ2VzdC3DoC1kaXJlIHF1ZSwgbW9pbnMgbGVzIHNvbHMgc29udCBhcnRpZmljaWFsaXPDqXMsIHBsdXMgbGEgZGl2ZXJzaXTDqSBlc3QgZ3JhbmRlIGF2ZWMgdW5lIGRpdmVyc2l0w6kgbWF4aW1hbGUgYXR0ZWludGUgcXVhbmQgbGUgbWlsaWV1IGVzdCDDoCBsYSBmb2lzIGFydGlmaWNpYWxpc8OpIG1haXMgcHLDqXNlbnRlIMOpZ2FsZW1lbnQgZGVzIHN1cmZhY2VzIG5vbiBhcnRpZmljaWFsaXPDqWVzLiANCg0KDQpOb3RyZSBkZXV4acOobWUgcGFydGllIHNlIHBvcnRlcmEgc3VyIGwnYW5hbHlzZSBkZSBsYSBkaXZlcnNpdMOpIGRlcyBlc3DDqGNlcyBkJ29pc2VhdXggZW4gZm9uY3Rpb24gZGUgbGEgZGlzdGFuY2UgYXZlYyBsZSBjZW50cmUtdmlsbGUgZGUgQm9yZGVhdXguDQpPbiBvYnNlcnZlcmEgdW5lIHRlbmRhbmNlIGRlIGRpdmVyc2l0w6kgcGFyIHJhcHBvcnQgw6AgbGEgZGlzdGFuY2UgZGUgbGEgbWFpbGxlIGF2ZWMgbGUgY2VudHJlIHZpbGxlIHF1aSBkaWZmw6hyZSBsw6lnw6hyZW1lbnQgcGFyIHJhcHBvcnQgYXV4IHLDqXN1bHRhdHMgY2ktZGVzc3VzLg0KUG91ciBjZSBmYWlyZSwgbm91cyBhbGxvbnMgY2FsY3VsZXIgdG91dGVzIGxlcyBkaXN0YW5jZXMgZGUgY2hhcXVlIG1haWxsZSDDoCBQZXlCZXJsYW5kLCBxdWkgc2VyYSBub3RyZSBwb2ludCByw6lmw6lyZW50IHBvdXIgbGUgY2VudHJlLiANCg0KIyBUZW5kYW5jZSBkZSBkaXZlcnNpdMOpIHBhciByYXBwb3J0IMOgIGxhIGRpc3RhbmNlIGF2ZWMgbGUgY2VudHJlLXZpbGxlDQoNCmBgYHtyfQ0KUGV5QmVybGFuZCA8LSBkYXRhLmZyYW1lKCJMYXRpdHVkZSIgPSA0NC44MzgxNjgsICJMb25naXR1ZGUiID0gLTAuNTc4ODAzKQ0KDQojIE9uIGNvbnZlcnRpdCBsZXMgY29vcmRvbm7DqWVzIGRlIFBleUJlcmxhbmQgZW4gc2YNCg0KUGV5QmVybGFuZCA8LSBzdF9hc19zZihQZXlCZXJsYW5kLCBjb29yZHMgPSBjKCJMb25naXR1ZGUiLCAiTGF0aXR1ZGUiKSwgY3JzID0gNDMyNikNCg0KIyBPbiB2YSBjcsOpZXIgdW4gZGF0YWZyYW1lIHF1aSBjb250aWVudCBsZXMgY29vcmRvbm7DqWVzIGRlIHRvdXRlcyBsZXMgc3RhdGlvbnMgY29kZV9tYWlsbGUNCg0KY29vcmRpbmF0ZXMgPC0gc3RfYXNfc2YoTFVQLCBjb29yZHMgPSBjKCJYIiwgIlkiKSwgY3JzID0gMjE1NCkNCg0KIyBPbiB2YSB0cmFuc2Zvcm1lciBsZXMgY29vcmRvbm7DqWVzIGRlIDIxNTQgw6AgNDMyNg0KDQpjb29yZGluYXRlcyA8LSBzdF90cmFuc2Zvcm0oY29vcmRpbmF0ZXMsIGNycyA9IDQzMjYpDQoNCiMgT24gdmEgY2FsY3VsZXIgbGVzIGRpc3RhbmNlcyBlbnRyZSBsZXMgc3RhdGlvbnMgZXQgbGUgY2VudHJlIHZpbGxlIFBleUJlcmxhbmQNCg0KY29vcmRpbmF0ZXMkRGlzdGFuY2UgPC0gc3RfZGlzdGFuY2UoY29vcmRpbmF0ZXMsIFBleUJlcmxhbmQpDQpgYGANCg0KT24gYWpvdXRlIGxlcyBkaXN0YW5jZXMgw6Agbm9zIGRvbm7DqWVzIGRlIGRpdmVyc2l0w6kuIA0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRX0NCmluZGV4JERpc3RhbmNlIDwtIHJlcChOQSwgbnJvdyhpbmRleCkpDQpmb3IgKGkgaW4gMTpucm93KGluZGV4KSkgew0KICBpbmRleCREaXN0YW5jZVtpXSA8LSBjb29yZGluYXRlcyREaXN0YW5jZVt3aGljaChpbmRleCRDb2RlX01haWxsZVtpXSA9PSBjb29yZGluYXRlcyRJRCAmIGNvb3JkaW5hdGVzJEJ1ZmZlclNpemUgPT0gNTAwKV0NCn0NCg0KcGFyKG1mcm93ID0gYygxLCAzKSkNCmBgYA0KDQpQb3VyIGZhaXJlIGwnYW5hbHlzZSwgb24gdXRpbGlzZSBsZXMgdHJvaXMgbWVzdXJlcyBkZSBkaXZlcnNpdMOpIHF1ZSBub3VzIGF2b25zIHV0aWxpc8OpZXMgcHLDqWPDqWRlbW1lbnQuDQoNCiMjIyBNZXN1cmUgZGUgbGEgZGl2ZXJzaXTDqSB7LnRhYnNldH0NCg0KIyMjIyBQcm9wb3J0aW9uIGQnZXNww6hjZXMNCg0KVm9pY2kgbGEgY291cmJlIGRlIGRpdmVyc2l0w6kgZXhwbGlxdcOpZSBwYXIgbGEgcHJvcG9ydGlvbiBkJ2VzcMOoY2VzLg0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGVycm9yPUZBTFNFfQ0KZ2dwbG90KGluZGV4LCBhZXMoeCA9IERpc3RhbmNlLCB5ID0gRDEsIGNvbG9yID0gYXMuZmFjdG9yKGFubmVlKSkpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMikgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAiYXV0byIsIHNlID0gVFJVRSwgY29sb3IgPSAiYmxhY2siLCBhbHBoYSA9IDAuMikgKw0KICBsYWJzKHRpdGxlID0gIlByb3BvcnRpb24gZCdlc3DDqGNlcyBlbiBmb25jdGlvbiBkZSBsYSBkaXN0YW5jZSBhdSBjZW50cmUtdmlsbGUiLA0KICAgICAgIHggPSAiRGlzdGFuY2UiLA0KICAgICAgIHkgPSAiUHJvcG9ydGlvbiBkJ2VzcMOoY2VzIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBsYWJzKGNvbG91ciA9ICJBbm7DqWUiKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQ0KYGBgDQoNCiMjIyMgSW5kaWNlIGRlIFNoYW5vbg0KDQpWb2ljaSBsYSBjb3VyYmUgZGUgZGl2ZXJzaXTDqSBleHBsaXF1w6llIHBhciBsJ2VudHJvcGllIGRlIFNoYW5ub24uDQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZXJyb3I9RkFMU0V9DQpnZ3Bsb3QoaW5kZXgsIGFlcyh4ID0gRGlzdGFuY2UsIHkgPSBEMiwgY29sb3IgPSBhcy5mYWN0b3IoYW5uZWUpKSkgKw0KICBnZW9tX3BvaW50KHNpemUgPSAyKSArDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJhdXRvIiwgc2UgPSBUUlVFLCBjb2xvciA9ICJibGFjayIsIGFscGhhID0gMC4yKSArDQogIGxhYnModGl0bGUgPSAiSW5kaWNlIGRlIFNoYW5vbiBlbiBmb25jdGlvbiBkZSBsYSBkaXN0YW5jZSBhdSBjZW50cmUtdmlsbGUiLA0KICAgICAgIHggPSAiRGlzdGFuY2UiLA0KICAgICAgIHkgPSAiSW5kaWNlIGRlIFNoYW5vbiIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgbGFicyhjb2xvdXIgPSAiQW5uw6llIikgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikNCmBgYA0KDQojIyMjIEluZGljZSBkZSBTaW1wc29uDQoNClZvaWNpIGxhIGNvdXJiZSBkZSBkaXZlcnNpdMOpIGV4cGxpcXXDqWUgcGFyIGwnaW5kaWNlIGRlIFNpbXBzb24uDQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZXJyb3I9RkFMU0V9DQpnZ3Bsb3QoaW5kZXgsIGFlcyh4ID0gRGlzdGFuY2UsIHkgPSBEMywgY29sb3IgPSBhcy5mYWN0b3IoYW5uZWUpKSkgKw0KICBnZW9tX3BvaW50KHNpemUgPSAyKSArDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJhdXRvIiwgc2UgPSBUUlVFLCBjb2xvciA9ICJibGFjayIsIGFscGhhID0gMC4yKSArDQogIGxhYnModGl0bGUgPSAiSW5kaWNlIGRlIFNpbXBzb24gZW4gZm9uY3Rpb24gZGUgbGEgZGlzdGFuY2UgYXUgY2VudHJlLXZpbGxlIiwNCiAgICAgICB4ID0gIkRpc3RhbmNlIiwNCiAgICAgICB5ID0gIkluZGljZSBkZSBTaW1wc29uIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBsYWJzKGNvbG91ciA9ICJBbm7DqWUiKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQ0KYGBgDQoNCiMjIw0KDQpMYSB0ZW5kYW5jZSBnbG9iYWxlIGVzdCBsJ2F1Z21lbnRhdGlvbiBkZSBsYSBkaXZlcnNpdMOpIGF1IGTDqWJ1dCBkZSBsYSBjb3VyYmUganVzcXUnw6AgYXR0ZWluZHJlIHVuIG1heGltdW0gcHVpcyB1bmUgYmFpc3NlIHF1YW5kIGxhIGRpc3RhbmNlIGF2ZWMgbGUgY2VudHJlLXZpbGxlIGF1Z21lbnRlIGRhdmFudGFnZS4gTm91cyBwb3V2b25zIHZvaXIgcXVlIHBvdXIgbm9zIHRyb2lzIG1lc3VyZXMgZGUgZGl2ZXJzaXTDqSwgbGUgcGljIGVzdCBhdHRlaW50IMOgIGVudmlyb24gOWttLiBMYSBkaXZlcnNpdMOpIGVzdCBkb25jIHBsdXMgZ3JhbmRlIGxvcnNxdWUgbGEgbWFpbGxlIHNlIHRyb3V2ZXIgw6AgZW52aXJvbiA5a20gZHUgY2VudHJlLXZpbGxlLg0KTm91cyByZXRyb3V2b25zIGRvbmMgbGEgbcOqbWUgb2JzZXJ2YXRpb24gcXUnYXZlYyBsYSB2YXJpYWJsZSBkJ2FydGlmaWNpYWxpc2F0aW9uIGRlcyBzb2xzIChNT1NTMTEpLCBjYXIgbCdhcnRpZmljaWFsaXNhdGlvbiBkZXMgc29scyBldCBsYSBkaXN0YW5jZSBhdmVjIGxlIGNlbnRyZSB2aWxsZSBzb250IHBvc2l0aXZlbWVudCBjb3Jyw6lsw6llcyAocGV1dC1ldHJlIGVzc2F5ZXIgZGUgbWVzdXJlciBsYSBjb3JyZWxhdGlvbiBlbnRyZSBjZXMgZGV1eCB2YXJpYWJsZXMgc3VyIG5vcyBkb25uw6llcykNCg0KDQpQYXIgbGEgc3VpdGUsIGwnb2JqZWN0aWYgdmEgw6p0cmUgZGUgY29tcHJlbmRyZSBwb3VycXVvaSBjZSBwaWMgZGUgZGl2ZXJzaXTDqSBkZXMgZXNww6hjZXMgZXN0IG9ic2VydsOpIMOgIGNlIHBvdXJjZW50YWdlIGQnYXJ0aWZpY2lhbGlzYXRpb24uIFBvdXIgY2UgZmFpcmUsIG5vdXMgYWxsb25zIGludHJvZHVpcmUgdW4gbm91dmVhdSBqZXUgZGUgZG9ubsOpZXMgc3VyIGxlcyBjYXJhY3TDqXJpc3RpcXVlcyBkZXMgZXNww6hjZXMgZCdvaXNlYXV4Lg0KTm91cyBhbGxvbnMgY29tYmluZXIgY2UgamV1IGRlIGRvbm7DqWVzIGF2ZWMgbGVzIGF1dHJlcyBqZXV4IGRlIGRvbm7DqWVzIGFmaW4gZCdlbiB0aXJlciBkZXMgYW5hbHlzZXMsIHByaW5jaXBhbGVtZW50IGdyw6JjZSDDoCBkZXMgY2FydGVzIGludGVyYWN0aXZlcy4gDQoNCg0KYGBge3J9DQpvaXNlYXV4IDwtIHJlYWQuY3N2KCJkYXRhL2JpcmRzL09pc2VhdXhfdXBfdG9fMjAyMy5jc3YiLCBoZWFkZXIgPSBUUlVFLCBzZXAgPSAiXHQiKQ0KTFVQIDwtIHJlYWQuY3N2KCJkYXRhL2JpcmRzL0xhbmRVc2VQZXJfQk1fMjAyM19jYXJ0b0lTZWEuY3N2IiwgaGVhZGVyID0gVFJVRSkNCmBgYA0KDQpgYGB7cn0NCiMgQ1LDiUVSIFVORSBOT1VWRUxMRSBDT0xPTk5FIERBTlMgTEUgREFUQUZSQU1FIE9JU0VBVVggUVVJIENPTlRJRU5UIExFIE5PTSBMQVRJTiBERSBMJ09JU0VBVQ0KIyBMRSBOT00gTEFUSU4gRVNUIExFIFBSRU1JRVIgTk9NIERFIExBIENPTE9OTkUgIk5vbV9UYXhvbl9DaXRlDQojIFNJIExFIE5PTSBDT05USUVOVCBVTiAifCIsIExFIE5PTSBMQVRJTiBFU1QgTEUgUFJFTUlFUiBOT00gQVZBTlQgTEUgInwiDQoNCiMgRGl2aXNlciBsZXMgbm9tcw0KbXlfc3BsaXQgPC0gZnVuY3Rpb24oYXJyYXksIHN0ciA9ICIgXFx8ICIpIHsNCiAgb3V0IDwtIHJlcChOQSwgbGVuZ3RoKGFycmF5KSkNCiAgZm9yIChpIGluIDE6bGVuZ3RoKGFycmF5KSkgew0KICAgIG91dFtpXSA8LSB1bmxpc3Qoc3Ryc3BsaXQoYXJyYXlbaV0sIHN0cikpWzFdDQogIH0NCiAgcmV0dXJuKG91dCkNCn0NCg0KIyBUZXN0ZXIgbGEgZm9uY3Rpb24NCm9ubHlfbGF0aW4gPC0gbXlfc3BsaXQoYXMudmVjdG9yKG9pc2VhdXgkTm9tX1RheG9uX0NpdGUpKQ0KDQojIE9uIGFqb3V0ZSBsYSBub3V2ZWxsZSBjb2xvbm5lIGF1IGRhdGFmcmFtZQ0Kb2lzZWF1eCRsYXRpbiA8LSBvbmx5X2xhdGluDQpgYGANCg0KVm9pY2kgbGUgdGFibGVhdSBxdWkgcmVwcsOpc2VudGUgbGUgTU9TMTEgcG91ciBjaGFxdWUgc3RhdGlvbiBkZSBtZXN1cmUuDQpDZXR0ZSBtZXN1cmUgbm91cyBpbmRpcXVlIMOgIHF1ZWwgcG9pbnQgbGUgc29sIGVzdCBhcnRpZmljaWFsaXPDqS4NCmBgYHtyfQ0KIyBDUsOJRVIgVU5FIE5PVVZFTExFIENPTE9OTkUgREFOUyBMRSBEQVRBRlJBTUUgT0lTRUFVWCBRVUkgQ09OVElFTlQgTEEgVkFMRVVSIE1PUzExIERVIFBPSU5UDQpmaWx0ZXIgPC0gTFVQJEJ1ZmZlclNpemUgPT0gNTAwDQpMVVBfNTAwX01PUzExIDwtIExVUFtmaWx0ZXIsIGMoIkdlb21ldHJ5IiwgIklEIiwgIlgiLCAiWSIsICJCdWZmZXJTaXplIiwgIk1PUzExIildDQpyb3duYW1lcyhMVVBfNTAwX01PUzExKSA8LSAxOm5yb3coTFVQXzUwMF9NT1MxMSkNCkxVUF81MDBfTU9TMTFbLCBjKCJJRCIsICJNT1MxMSIpXQ0KDQpNT1MxMSA8LSByZXAoTkEsIG5yb3cob2lzZWF1eCkpDQpmb3IgKGkgaW4gMTpucm93KG9pc2VhdXgpKSB7DQogIE1PUzExW2ldIDwtIHdoaWNoKG9pc2VhdXgkQ29kZV9NYWlsbGVbaV0gPT0gTFVQXzUwMF9NT1MxMSRJRCkNCn0NCg0KIyBBam91dGVyIGxhIGNvbG9ubmUgTU9TMTEgYXUgZGF0YWZyYW1lDQpvaXNlYXV4JE1PUzExIDwtIExVUF81MDBfTU9TMTEkTU9TMTFbTU9TMTFdDQpgYGANCg0KIyBBbmFseXNlcyBpbnTDqXJhY3RpdmVzIGV0IGfDqW9ncmFwaGlxdWVzDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpvaXNlYXV4IDwtIHJlYWQuY3N2KCJkYXRhL2JpcmRzL09pc2VhdXhfdXBfdG9fMjAyMy5jc3YiLCBoZWFkZXIgPSBUUlVFLCBzZXAgPSAiXHQiKQ0KIyBDUkVBVEUgQSBORVcgQ09MVU1OIElOIFRIRSBPSVNFQVVYIERBVEFGUkFNRSBUSEFUIENPTlRBSU5TIFRIRSBMQVRJTiBOQU1FIE9GIFRIRSBCSVJEDQpteV9zcGxpdCA8LSBmdW5jdGlvbihhcnJheSwgc3RyID0gIiBcXHwgIikgew0KICBvdXQgPC0gcmVwKE5BLCBsZW5ndGgoYXJyYXkpKQ0KICBmb3IgKGkgaW4gMTpsZW5ndGgoYXJyYXkpKSB7DQogICAgb3V0W2ldIDwtIHVubGlzdChzdHJzcGxpdChhcnJheVtpXSwgc3RyKSlbMV0NCiAgfQ0KICByZXR1cm4gKG91dCkNCn0NCg0Kb25seV9sYXRpbiA8LSBteV9zcGxpdChhcy52ZWN0b3Iob2lzZWF1eCROb21fVGF4b25fQ2l0ZSkpDQojIGxlbmd0aCh1bmlxdWUob25seV9sYXRpbikpID09IGxlbmd0aCh1bmlxdWUob2lzZWF1eCRDb2RlX1JlZikpDQoNCm9pc2VhdXgkbGF0aW4gPC0gb25seV9sYXRpbg0Kb2lzZWF1eCRhbm5lZSA8LSBhcy5udW1lcmljKHN1YnN0cihvaXNlYXV4JERhdGUsIDEsIDQpKQ0KDQpkZW5vbWJyZW1lbnQgPC0gb2lzZWF1eCAlPiUNCiAgZ3JvdXBfYnkoQ29kZV9NYWlsbGUsIGFubmVlLCBsYXRpbikgJT4lDQogIHN1bW1hcmlzZShzdW0gPSBzdW0oRGVub21icmVtZW50X21pbiwgbmEucm0gPSBUUlVFKSwgLmdyb3VwcyA9ICdkcm9wJykgJT4lDQogIGFycmFuZ2UoZGVzYyhDb2RlX01haWxsZSkpDQoNCmRlbm9tYnJlbWVudCRwIDwtIHJlcChOQSwgbnJvdyhkZW5vbWJyZW1lbnQpKQ0KZm9yIChpIGluIDE6bnJvdyhkZW5vbWJyZW1lbnQpKSB7DQogIG51bWVyYXRvciA8LSBkZW5vbWJyZW1lbnQkc3VtW2ldDQogIGRlbm9taW5hdG9yIDwtIA0KICAgIHN1bShkZW5vbWJyZW1lbnQkc3VtW3doaWNoKGRlbm9tYnJlbWVudCRDb2RlX01haWxsZSA9PSBkZW5vbWJyZW1lbnQkQ29kZV9NYWlsbGVbaV0gDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJiBkZW5vbWJyZW1lbnQkYW5uZWUgPT0gZGVub21icmVtZW50JGFubmVlW2ldKV0pDQogIGRlbm9tYnJlbWVudCRwW2ldIDwtIG51bWVyYXRvciAvIGRlbm9taW5hdG9yDQp9DQoNCmluZGV4IDwtIGRlbm9tYnJlbWVudCAlPiUNCiAgZ3JvdXBfYnkoQ29kZV9NYWlsbGUsIGFubmVlID0gZmFjdG9yKGFubmVlKSkgJT4lDQogIHN1bW1hcmlzZShEMSA9IHN1bShwID4gMCwgbmEucm0gPSBUUlVFKSwgDQogICAgICAgICAgICBEMiA9IGV4cCgtc3VtKHAqbG9nKHApKSksIA0KICAgICAgICAgICAgRDMgPSAxIC8gc3VtKHBeMiksIC5ncm91cHMgPSAnZHJvcCcpICU+JQ0KICBhcnJhbmdlKGRlc2MoQ29kZV9NYWlsbGUpKQ0KDQpMVVAgPC0gcmVhZC5jc3YoImRhdGEvYmlyZHMvTGFuZFVzZVBlcl9CTV8yMDIzX2NhcnRvSVNlYS5jc3YiLCBoZWFkZXIgPSBUUlVFKQ0KaW5kZXgkTU9TMTEgPC0gcmVwKE5BLCBucm93KGluZGV4KSkNCmZvciAoaSBpbiAxOm5yb3coaW5kZXgpKSB7DQogIGluZGV4JE1PUzExW2ldIDwtIExVUCRNT1MxMVt3aGljaChpbmRleCRDb2RlX01haWxsZVtpXSA9PSBMVVAkSUQgJiBMVVAkQnVmZmVyU2l6ZSA9PSAxMDAwKV0NCn0NCg0KDQp0cmFpdHMgPC0gcmVhZC5jc3YoImRhdGEvYmlyZHMvdHJhaXRzLXN0YXR1dC1JVUNOLWJpb2RpdmVyY2l0ZS5jc3YiLCBoZWFkZXIgPSBUUlVFKQ0KY2l0ZSA8LSByZWFkLmNzdigiZGF0YS9iaXJkcy9CaW9kaXZlckNpdGVfc2l0ZXMuY3N2IiwgaGVhZGVyID0gVFJVRSwgc2VwPSI7IikNCg0KI29uIHZldXQgdHJhaXRlciBsYSB0YWJsZSBkw6lub21icmVtZW50IHF1J29uIGFwcGVsZXJhIGRlbm9tYnJlbWVudENhcnRlIG/DuSBpbCByZXN0ZXJhIHBvdXIgY2hhcXVlIG1haWxsZSBldCBwb3VyIGNoYXF1ZSBhbm7DqWUgbGUgdG9wIDMgZGVzIG9pc2VhdXggbGVzIHBsdXMgb2JzZXJ2w6lzIHNhbnMgbGEgdmFyaWFibGUgcA0KDQpkZW5vbWJyZW1lbnRDYXJ0ZSA8LSBkZW5vbWJyZW1lbnQgJT4lDQogIGdyb3VwX2J5KENvZGVfTWFpbGxlLCBhbm5lZSkgJT4lDQogIHRvcF9uKDMsIHN1bSkgJT4lDQogIGFycmFuZ2UoQ29kZV9NYWlsbGUsIGFubmVlLCBkZXNjKHN1bSkpICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogIHNlbGVjdCgtcCkNCg0KDQojb24gdmV1dCBjaGFuZ2VyIGNldHRlIHRhYmxlIHBvdXIgZmFpcmUgYXBwYXJhaXRyZSBkZSBub3V2ZWxsZXMgY29sb25uZXMgcG91ciBxdSdpbCB5IGFpdCA6IHVuZSBsaWduZSBwYXIgbWFpbGxlIGV0IHBhciBhbm7DqWUsIGV0IHBvdXIgY2hhcXVlIG9pc2VhdSwgbGUgbm9tYnJlIGQnaW5kaXZpZHVzIG9ic2VydsOpcw0KDQpkZW5vbWJyZW1lbnRDYXJ0ZSA8LSBkZW5vbWJyZW1lbnRDYXJ0ZSAlPiUNCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGxhdGluLCB2YWx1ZXNfZnJvbSA9IHN1bSwgdmFsdWVzX2ZpbGwgPSAwKQ0KDQoNCiNvbiB2ZXV0IGFqb3V0ZXIgbGVzIGNvbG9ubmVzIGdlb21ldHJ5LCBidWZmZXIgc2l6ZSBldCBNT1MxMSDDoCBsYSB0YWJsZSBkZW5vbWJyZW1lbnRDYXJ0ZSBldCBwYXMgbGVzIGF1dHJlcw0KDQpkZW5vbWJyZW1lbnRDYXJ0ZSA8LSBsZWZ0X2pvaW4oZGVub21icmVtZW50Q2FydGUsIExVUCwgYnkgPSBjKCJDb2RlX01haWxsZSIgPSAiSUQiKSkNCg0KI29uIGVubMOodmUgbGVzIGNvbG9ubmVzIDogTU9TMSwgTU9TMiwgTU9TMywgTU9TNCwgTU9TNSwgTU9TNiwgTU9TNywgTU9TOCwgTU9TOSwgTU9TMTAsIE1PUzEyLCBNT1MxMywgTU9TMTQNCg0KZGVub21icmVtZW50Q2FydGUgPC0gZGVub21icmVtZW50Q2FydGUgJT4lDQogIHNlbGVjdCgtYyhNT1MxLCBNT1MyLCBNT1MzLCBNT1M0LCBNT1M1LCBNT1M2LCBNT1M3LCBNT1M4LCBNT1M5LCBNT1MxMCwgTU9TMTIsIE1PUzEzLCBNT1MxNCkpDQoNCiMgT24gZ2FyZGUgcXVlIGxlcyBsaWduZXMgb3UgQnVmZmVyU2l6ZSA9PSA1MDANCmRlbm9tYnJlbWVudENhcnRlIDwtIGRlbm9tYnJlbWVudENhcnRlICU+JQ0KICBmaWx0ZXIoQnVmZmVyU2l6ZSA9PSA1MDApDQoNCmRlbm9tYnJlbWVudENhcnRlIDwtIHN0X2FzX3NmKGRlbm9tYnJlbWVudENhcnRlLCBjb29yZHMgPSBjKCJYIiwgIlkiKSwgY3JzID0gMjE1NCkNCmRlbm9tYnJlbWVudENhcnRlIDwtIHN0X3RyYW5zZm9ybShkZW5vbWJyZW1lbnRDYXJ0ZSwgY3JzID0gNDMyNikNCg0KIyBPbiBnYXJkZSBzZXVlbGVtZW50IGxlcyB2YWxldXJzIG91IGFubmVlID0gMjAxOA0KDQpkZW5vbWJyZW1lbnRDYXJ0ZSA8LSBkZW5vbWJyZW1lbnRDYXJ0ZSAlPiUNCiAgZmlsdGVyKGFubmVlID09IDIwMjMpDQoNCmRlbm9tYnJlbWVudENhcnRlDQpgYGANCkdyw6JjZSDDoCBjZSB0YWJsZWF1LCBub3VzIHBvdXZvbnMgdm9pciBjb21tZW50IGxlcyBkb25uw6llcyBzb250IHN0cnVjdHVyw6llcyBldCByZW1hcnF1ZXIgbm90YW1tZW50IHF1J2lsIGNsYXNzZSBsZSBub21icmUgZCdvaXNlYXV4IHBhciBtYWlsbGUgZXQgcGFyIGFubsOpZS4NCg0KDQpEYW5zIGxhIHN1aXRlIGRlIGNlIHJhcHBvcnQgdm91cyB0cm91dmVyZXogZGVzIGFuYWx5c2VzIGfDqW9ncmFwaGlxdWVzIGV0IGludGVyYWN0aXZlcyBxdWkgdm91cyBwZXJtZXR0cm9udCBkZSB2aXN1YWxpc2VyIGNvbW1lbnQgbGVzIG9pc2VhdXggZGUgbGEgR2lyb25kZSDDqXZvbHVlbnQgZW4gZm9uY3Rpb24gZGUgbCdhcnRpZmljaWFsaXNhdGlvbiBkZXMgc29scy4NClZvdXMgeSB0cm91dmVyZXogZGVzIGFuYWx5c2VzIHN1ciBsZXMgcsOpZ2ltZXMgYWxpbWVudGFpcmVzIGRlcyBvaXNlYXV4LCBsZXMgbml2ZWF1eCBkZSBzcMOpY2lhbGlzYXRpb24gZGVzIG9pc2VhdXggZW4gZm9uY3Rpb24gZGUgbGV1ciBoYWJpdGF0IChNYWlsbGUpLg0KDQpWb2ljaSBsYSBjYXJ0ZSBpbnRlcmFjdGl2ZSBxdWkgbW9udHJlIGxlcyBtYWlsbGVzIGRlIG1lc3VyZSBldCBsZXMgb2lzZWF1eCBsZXMgcGx1cyBvYnNlcnbDqXMgZGFucyBjaGFxdWUgbWFpbGxlLg0KTm91cyB2b3VzIGludml0b25zIMOgIGNsaXF1ZXIgc3VyIGxlcyBjZXJjbGVzIHBvdXIgb2J0ZW5pciB0b3V0ZXMgbGVzIGluZm9ybWF0aW9ucyBzdXIgbGVzIG9pc2VhdXguDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBPbiBnYXJkZXIgcXVlIGxlcyBjb2xvbm5lcyBxdWkgbm91cyBpbnTDqXJlc3NlbnQsIGNhZCBjb2RlX3NpdGUgZXQgTm9tX2xpZXUNCg0KY2l0ZSA8LSByZWFkLmNzdigiZGF0YS9iaXJkcy9CaW9kaXZlckNpdGVfc2l0ZXMuY3N2IiwgaGVhZGVyID0gVFJVRSwgc2VwPSI7IikNCmNpdGUgPC0gY2l0ZSAlPiUNCiAgc2VsZWN0KGNvZGVfc2l0ZSwgTm9tX2xpZXUpDQoNCiNPbiBqb2luIGxlcyBkZXV4IHRhYmxlcyBjaXRlIGV0IGRlbm9tYnJlbWVudENhcnRlDQoNCmRlbm9tYnJlbWVudENhcnRlIDwtIGxlZnRfam9pbihkZW5vbWJyZW1lbnRDYXJ0ZSwgY2l0ZSwgYnkgPSBjKCJDb2RlX01haWxsZSIgPSAiY29kZV9zaXRlIikpDQoNCiMgQ3LDqWVyIHVuZSBjaGHDrm5lIGRlIGNhcmFjdMOocmVzIHBvdXIgbGVzIHBvcHVwcyBhdmVjIGxlIHRvcCB0cm9pcyBkZXMgb2lzZWF1eCBheWFudCBsYSBwbHVzIGdyYW5kZSB2YWxldXINCmRlbm9tYnJlbWVudENhcnRlJHBvcHVwX3RleHQgPC0gcGFzdGUwKCI8c3Ryb25nPk1haWxsZTo8L3N0cm9uZz4gIiwgZGVub21icmVtZW50Q2FydGUkTm9tX2xpZXUsICI8YnI+IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjxzdHJvbmc+QW5uw6llOjwvc3Ryb25nPiAiLCBkZW5vbWJyZW1lbnRDYXJ0ZSRhbm5lZSwgIjxicj4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiPHN0cm9uZz5Ub3AgMyBkZXMgb2lzZWF1eDo8L3N0cm9uZz4iLCAiPGJyPiIpDQoNCmRhdGFmcmFtZSA8LSBhcy5kYXRhLmZyYW1lKGRlbm9tYnJlbWVudENhcnRlKQ0KDQojIE9uIGVubGV2ZSBsZXMgY29sb25uZXMgQ29kZV9NYWlsbGUsIGFubmVlLCBCdWZmZXJTaXplLCBNT1MxMSwgR2VvbWV0cnksIGdlb21ldHJ5DQpkYXRhZnJhbWUgPC0gZGF0YWZyYW1lICU+JQ0KICBzZWxlY3QoLWMoQ29kZV9NYWlsbGUsIGFubmVlLCBCdWZmZXJTaXplLCBNT1MxMSwgR2VvbWV0cnksIGdlb21ldHJ5LCBOb21fbGlldSkpDQoNCiMgQWpvdXRlciBsZXMgbm9tcyBkZXMgb2lzZWF1eCBldCBsZXVycyB2YWxldXJzIGF1IHBvcHVwX3RleHQgcG91ciBjaGFxdWUgbGlnbmUNCmZvciAoaSBpbiAxOm5yb3coZGF0YWZyYW1lKSkgew0KICB0b3BfYmlyZHMgPC0gc29ydCh1bmxpc3QoZGF0YWZyYW1lW2ksIC1jKG5jb2woZGF0YWZyYW1lKSldKSwgZGVjcmVhc2luZyA9IFRSVUUpWzE6M10NCiAgdG9wX2JpcmRfbmFtZXMgPC0gbmFtZXModG9wX2JpcmRzKQ0KICBkZW5vbWJyZW1lbnRDYXJ0ZSRwb3B1cF90ZXh0W2ldIDwtIHBhc3RlMChkZW5vbWJyZW1lbnRDYXJ0ZSRwb3B1cF90ZXh0W2ldLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b3BfYmlyZF9uYW1lc1sxXSwgIjogIiwgdG9wX2JpcmRzWzFdLCAiIC0gIiwgdHJhaXRzW3doaWNoKHRyYWl0cyROb20ubGF0aW4gPT0gdG9wX2JpcmRfbmFtZXNbMV0pLCAiTml2ZWF1LmRlLnNww6ljaWFsaXNhdGlvbiJdLCAiPGJyPiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvcF9iaXJkX25hbWVzWzJdLCAiOiAiLCB0b3BfYmlyZHNbMl0sICIgLSAiLCB0cmFpdHNbd2hpY2godHJhaXRzJE5vbS5sYXRpbiA9PSB0b3BfYmlyZF9uYW1lc1syXSksICJOaXZlYXUuZGUuc3DDqWNpYWxpc2F0aW9uIl0sICI8YnI+IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9wX2JpcmRfbmFtZXNbM10sICI6ICIsIHRvcF9iaXJkc1szXSwgIiAtICIsIHRyYWl0c1t3aGljaCh0cmFpdHMkTm9tLmxhdGluID09IHRvcF9iaXJkX25hbWVzWzNdKSwgIk5pdmVhdS5kZS5zcMOpY2lhbGlzYXRpb24iXSkNCn0NCg0KcGFsIDwtIGNvbG9yTnVtZXJpYygidmlyaWRpcyIsIGRvbWFpbiA9IGRlbm9tYnJlbWVudENhcnRlJE1PUzExKQ0KDQoNCmxlYWZsZXQoZGF0YSA9IGRlbm9tYnJlbWVudENhcnRlKSAlPiUNCiAgYWRkUHJvdmlkZXJUaWxlcygiQ2FydG9EQi5Qb3NpdHJvbiIpICU+JQ0KICBhZGRDaXJjbGVzKHJhZGl1cyA9IDMwMCwgY29sb3IgPSB+cGFsKE1PUzExKSwgZmlsbE9wYWNpdHkgPSAwLjIsIHBvcHVwID0gfnBvcHVwX3RleHQpICU+JQ0KICBhZGRMZWdlbmQoImJvdHRvbXJpZ2h0IiwgcGFsID0gcGFsLCB2YWx1ZXMgPSB+TU9TMTEsIHRpdGxlID0gIk1PUzExIiwgcG9zaXRpb24gPSAiYm90dG9tcmlnaHQiKSAlPiUNCiAgYWRkU2NhbGVCYXIocG9zaXRpb24gPSAiYm90dG9tbGVmdCIpDQpgYGANCkdyw6JjZSDDoCBjZXR0ZSBjYXJ0ZSwgbm91cyBvYnRlbm9ucyBsZSBjbGFzc2VtZW50IChUb3AgMykgZGVzIG9pc2VhdXggbGVzIHBsdXMgb2JzZXJ2w6lzIGRhbnMgY2hhcXVlIG1haWxsZSBkZSBtZXN1cmUgcG91ciBsJ2FubsOpZSAyMDIzLg0KTm91cyBhdm9ucyDDqWdhbGVtZW50IGFqb3V0w6kgdW5lIGluZm9ybWF0aW9uIHN1cHBsw6ltZW50YWlyZSBzdXIgY2hhcXVlIG9pc2VhdSBwb3VyIG1ldHRyZSBlbiDDqXZpZGVuY2Ugc29uIG5pdmVhdSBkZSBzcMOpY2lhbGlzYXRpb24gYWZpbiBkZSBtaWV1eCBjb21wcmVuZHJlIGRlIHF1ZWwgdHlwZSBkZSBtaWxpZXUgaWwgYSBiZXNvaW4gcG91ciB2aXZyZSBldCBsYSBnw6lvbG9jYWxpc2F0aW9uIHN1ciBsYSBHaXJvbmRlLg0KDQpOb3VzIHBvdXZvbnMgdm9pciBxdWUgbGUgbml2ZWF1IGRlIHNww6ljaWFsaXNhdGlvbiBsZSBwbHVzIHLDqXBlbmR1IGVzdCBnw6luw6lyYWxpc3RlIGNhciBvbiBlbiByZXRyb3V2ZSBhdSBjZW50cmUtdmlsbGUgZXQgZW4gcMOpcmlwaMOpcmllLg0KRWdhbGVtZW50LCBhdSBjZW50cmUgdmlsbGUsIG9uIHJldHJvdXZlIGRlcyBvaXNlYXV4IGRlIHR5cGUgQsOidGkgZXQgZW4gcMOpcmlwaMOpcmllIGxvaW5zIGR1IGNlbnRyZS12aWxsZSwgb24gcmV0cm91dmUgZGVzIG9pc2VhdXggZGUgdHlwZSBGw7RyZXQgZXQgQWdyaWNvbGUuIFByb2NoZSBkZXMgcG9pbnRzIGQnZWF1LCBvbiB0cm91dmUgZGVzIG9pc2VhdXggZGUgdHlwZSBab25lIGh1bWlkZS4gDQoNCkFpbnNpLCBsZXMgem9uZXMgcXVpIGNvbWJpbmVudCDDoCBsYSBmb2lzIHbDqWfDqXRhdGlvbiBldCBiw6J0aW1lbnRzIHNlcmFpZW50IHBsdXMgc3VzY2VwdGlibGVzIGQnYWNjdWVpbGxpciBkZXMgb2lzZWF1eCBhdmVjIGRlcyBuaXZlYXV4IGRlIHNww6ljaWFsaXNhdGlvbiB2YXJpw6lzLCBjZSBxdWkgZXhwbGlxdWVyYWl0IGwnYXVnbWVudGF0aW9uIGR1IHRhdXggZGUgZGl2ZXJzaXTDqSBvYnNlcnbDqWUgZGFucyBsZXMgem9uZXMgb8O5IHNlIG3DqWxhbmdlbnQgZXNwYWNlcyB2ZXJ0cyBldCB6b25lcyB1cmJhbmlzw6llcy4NCg0KSWwgbm91cyBzZW1ibGFpdCBpbnTDqXJlc3NhbnQgZGUgc2F2b2lyIHF1ZWxzIMOpdGFpZW50IGxlcyByw6lnaW1lcyBhbGltZW50YWlyZXMgbWFqb3JpdGFpcmVzIHByaW5jaXBhdXggZW4gZm9uY3Rpb24gZGUgY2hhcXVlIG1haWxsZS4NCk5vdXMgYXZvbnMgZG9uYyBjcsOpw6kgdW4gZ3JhcGhpcXVlIHF1aSBtb250cmUgbGEgcsOpcGFydGl0aW9uIGRlcyByw6lnaW1lcyBhbGltZW50YWlyZXMgcG91ciBjaGFxdWUgbWFpbGxlLg0KDQpgYGB7cn0NCiMgY2hhbmdlZCB0aGUgdW5tYXRjaGlubmcgbGF0aW4gbmFtZXMgdG8gdGhlIGNvcnJlY3Qgb25lcyB0byBtYXRjaCBhbGltZW50YXRpb24NCmRlbm9tYnJlbWVudCRsYXRpbltkZW5vbWJyZW1lbnQkbGF0aW4gPT0gIkNhcmR1ZWxpcyBjaGxvcmlzIl0gPC0gIkNobG9yaXMgY2hsb3JpcyINCmRlbm9tYnJlbWVudCRsYXRpbltkZW5vbWJyZW1lbnQkbGF0aW4gPT0gIkNhcmR1ZWxpcyBzcGludXMiXSA8LSAiU3BpbnVzIHNwaW51cyINCmRlbm9tYnJlbWVudCRsYXRpbltkZW5vbWJyZW1lbnQkbGF0aW4gPT0gIkNhc21lcm9kaXVzIGFsYnVzIl0gPC0gIkFyZGVhIGFsYmEiDQpkZW5vbWJyZW1lbnQkbGF0aW5bZGVub21icmVtZW50JGxhdGluID09ICJDYXJkdWVsaXMgY2FubmFiaW5hIl0gPC0gIkxpbmFyaWEgY2FubmFiaW5hIg0Kbm9faW5mbyA8LSBjKCJIaW1hbnRvcHVzIGhpbWFudG9wdXMiLCAiVHJpbmdhIG9jaHJvcHVzIiwgDQogICAgICAgICAgICAgIkNhcHJpbXVsZ3VzIGV1cm9wYWV1cyIsICJMYW5pdXMgc2VuYXRvciIsIA0KICAgICAgICAgICAgICJEcnlvY29wdXMgbWFydGl1cyIsICJFbWJlcml6YSBjYWxhbmRyYSIpDQoNCmFsaW1lbnRhdGlvbiA8LSByZWFkLmNzdigiZGF0YS9iaXJkcy90cmFpdHMtc3RhdHV0LUlVQ04tYmlvZGl2ZXJjaXRlLmNzdiIsIGhlYWRlciA9IFRSVUUpDQpkZW5vbWJyZW1lbnQkcmVnaW1lX2FsaW1lbnRhaXJlIDwtIHJlcChOQSwgbnJvdyhkZW5vbWJyZW1lbnQpKQ0KZm9yIChpIGluIDE6bnJvdyhkZW5vbWJyZW1lbnQpKSB7DQogIGlmIChkZW5vbWJyZW1lbnQkbGF0aW5baV0gJWluJSBub19pbmZvKXsNCiAgICBkZW5vbWJyZW1lbnQkcmVnaW1lX2FsaW1lbnRhaXJlW2ldIDwtIE5BDQogIH0NCiAgZWxzZSB7DQogICAgZGVub21icmVtZW50JHJlZ2ltZV9hbGltZW50YWlyZVtpXSA8LSANCiAgICAgIGFsaW1lbnRhdGlvbiRSw6lnaW1lLmFsaW1lbnRhaXJlW3doaWNoKGFsaW1lbnRhdGlvbiROb20ubGF0aW4gPT0gZGVub21icmVtZW50JGxhdGluW2ldKV0NCiAgfQ0KfQ0KZGVub21icmVtZW50JHJlZ2ltZV9hbGltZW50YWlyZSA8LSBhcy5mYWN0b3IoZGVub21icmVtZW50JHJlZ2ltZV9hbGltZW50YWlyZSkNCg0KcGxvdF9kYXRhID0gZnVuY3Rpb24gKGRhdGEsIHRpdGxlKSB7DQogICAgZ2dwbG90KGRhdGEsIGFlcyh4PSIiLCB5PXN1bSwgZmlsbD1yZWdpbWVfYWxpbWVudGFpcmUpKSArDQogICAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCB3aWR0aD0wLjEpICsNCiAgICBjb29yZF9wb2xhcigieSIsIHN0YXJ0PTApICsNCiAgICBnZ3RpdGxlKHBhc3RlKCJTdGF0aW9uOiAiLCBhcy5jaGFyYWN0ZXIodGl0bGUpKSkgKw0KICAgIHRoZW1lX3ZvaWQoKQ0KfQ0KDQpjaXRlIDwtIGNpdGUgJT4lDQogIHNlbGVjdChjb2RlX3NpdGUsIE5vbV9saWV1KQ0KDQojT24gam9pbiBsZXMgZGV1eCB0YWJsZXMgY2l0ZSBldCBkZW5vbWJyZW1lbnRDYXJ0ZQ0KDQpkZW5vbWJyZW1lbnQgPC0gbGVmdF9qb2luKGRlbm9tYnJlbWVudCwgY2l0ZSwgYnkgPSBjKCJDb2RlX01haWxsZSIgPSAiY29kZV9zaXRlIikpDQoNCk4gPC0gbGVuZ3RoKHVuaXF1ZShkZW5vbWJyZW1lbnQkQ29kZV9NYWlsbGUpKQ0KcCA8LSB2ZWN0b3IoImxpc3QiLCBsZW5ndGggPSBOKQ0KDQpmb3IgKGkgaW4gMTpOKSB7DQogICAgZGF0YSA8LSBkZW5vbWJyZW1lbnRbd2hpY2goZGVub21icmVtZW50JENvZGVfTWFpbGxlID09IHVuaXF1ZShkZW5vbWJyZW1lbnQkQ29kZV9NYWlsbGUpW2ldKSxdDQogICAgZGF0YSA8LSBkYXRhICU+JSBncm91cF9ieShyZWdpbWVfYWxpbWVudGFpcmUpICU+JSBzdW1tYXJpc2Uoc3VtID0gc3VtKHAsIG5hLnJtID0gVFJVRSkpDQogICAgcFtbaV1dIDwtIHBsb3RfZGF0YShkYXRhLCB1bmlxdWUoZGVub21icmVtZW50JE5vbV9saWV1KVtpXSkNCn0NCg0KY29vcmRpbmF0ZXMgPC0gc3RfYXNfc2YoTFVQLCBjb29yZHMgPSBjKCJYIiwgIlkiKSwgY3JzID0gMjE1NCkNCmNvb3JkaW5hdGVzIDwtIHN0X3RyYW5zZm9ybShjb29yZGluYXRlcywgY3JzID0gNDMyNikNCmNvb3JkaW5hdGVzIDwtIGNvb3JkaW5hdGVzW2Nvb3JkaW5hdGVzJEJ1ZmZlclNpemUgPT0gNTAwLF0NCg0KIyBSZW1vdmUgdGhlIGNvb3JkaW5hdGVzIHRoYXQgYXJlIG5vdCBpbiBkZW5vbWJyZW1lbnQNCmZvciAoaSBpbiBzZXFfYWxvbmcoY29vcmRpbmF0ZXMkSUQpKXsNCiAgaWYgKCEoY29vcmRpbmF0ZXMkSURbaV0gJWluJSB1bmlxdWUoZGVub21icmVtZW50JENvZGVfTWFpbGxlKSkpew0KICAgIGNvb3JkaW5hdGVzIDwtIGNvb3JkaW5hdGVzWy1pLF0NCiAgfQ0KfQ0KDQpjb29yZGluYXRlcyA8LSBjb29yZGluYXRlc1tvcmRlcihjb29yZGluYXRlcyRJRCwgZGVjcmVhc2luZyA9IFRSVUUpLF0NCg0KcGFsIDwtIGNvbG9yTnVtZXJpYygidmlyaWRpcyIsIGRvbWFpbiA9IGNvb3JkaW5hdGVzJE1PUzExKQ0KbGVhZmxldChkYXRhID0gY29vcmRpbmF0ZXMpICU+JQ0KICBhZGRQcm92aWRlclRpbGVzKCJDYXJ0b0RCLlBvc2l0cm9uIikgJT4lDQogIGFkZENpcmNsZXMocmFkaXVzID0gMzAwLCBjb2xvciA9IH5wYWwoTU9TMTEpLCANCiAgICAgICAgICAgICBmaWxsT3BhY2l0eSA9IDAuNSwgZ3JvdXAgPSAicG50IikgJT4lDQogIGFkZExlZ2VuZCgiYm90dG9tcmlnaHQiLCBwYWwgPSBwYWwsIHZhbHVlcyA9IGNvb3JkaW5hdGVzJE1PUzExLCB0aXRsZSA9ICJNT1MxMSIpICU+JQ0KICBhZGRTY2FsZUJhcihwb3NpdGlvbiA9ICJib3R0b21sZWZ0IikgJT4lIA0KICBhZGRQb3B1cEdyYXBocyhwLCB3aWR0aCA9IDIwMCwgaGVpZ2h0ID0gMjAwLCBncm91cCA9ICJwbnQiKQ0KYGBgDQoNClZvaWNpIMOgIHF1b2kgcmVzc2VtYmxlIGxhIGNhcnRlIGludGVyYWN0aXZlIHF1aSBtb250cmUgbGVzIHLDqWdpbWVzIGFsaW1lbnRhaXJlcyBtYWpvcml0YWlyZXMgcHJpbmNpcGF1eCBlbiBmb25jdGlvbiBkZSBjaGFxdWUgbWFpbGxlLiBOb3VzIHBvdXZvbnMgdm9pciBxdSdlbiBnw6luw6lyYWwsIGxlIHLDqWdpbWUgYWxpbWVudGFpcmUgZG9taW5hbnQgZXN0IGxlIHLDqWdpbWUgYWxpbWVudGFpcmUgbWl4dGUsIHF1ZSBjZWxhIHNvaXQgYXUgY2VudHJlIGRlIEJvcmRlYXV4IG91IGVuIHDDqXJpcGjDqXJpZS4gSWwgc2VtYmxlIGRvbmMgcXVlIGxlIHLDqWdpbWUgYWxpbWVudGFpcmUgZGUgbCdvaXNlYXUgbmUgc29pdCBwYXMgdsOpcml0YWJsZW1lbnQgaW1wYWN0w6kgcGFyIGwnYXJ0aWZpY2lhbGlzYXRpb24gZGVzIHNvbHMuDQpFc3NheW9ucyBtYWludGVuYW50IGQnw6l0dWRpZXIgZCdhdXRyZSBjYXJhdMOpcmlzdGlxdWVzIGFmaW4gZCdlc3NheWVyIGRlIHRyb3V2ZXIgZGVzIHJhaXNvbnMgw6AgY2UgcGljIGRlIGRpdmVyc2l0w6kuDQoNCmBgYHtyfQ0KZGVub21icmVtZW50JE5pZGlmaWNhdGlvbiA8LSByZXAoTkEsIG5yb3coZGVub21icmVtZW50KSkNCmZvciAoaSBpbiAxOm5yb3coZGVub21icmVtZW50KSkgew0KICBpZiAoZGVub21icmVtZW50JGxhdGluW2ldICVpbiUgbm9faW5mbyl7DQogICAgZGVub21icmVtZW50JE5pZGlmaWNhdGlvbltpXSA8LSBOQQ0KICB9DQogIGVsc2Ugew0KICAgIGRlbm9tYnJlbWVudCROaWRpZmljYXRpb25baV0gPC0gDQogICAgICBhbGltZW50YXRpb24kTmlkaWZpY2F0aW9uW3doaWNoKGFsaW1lbnRhdGlvbiROb20ubGF0aW4gPT0gZGVub21icmVtZW50JGxhdGluW2ldKV0NCiAgfQ0KfQ0KZGVub21icmVtZW50JE5pZGlmaWNhdGlvbiA8LSBhcy5mYWN0b3IoZGVub21icmVtZW50JE5pZGlmaWNhdGlvbikNCg0KcGxvdF9kYXRhID0gZnVuY3Rpb24gKGRhdGEsIHRpdGxlKSB7DQogICAgZ2dwbG90KGRhdGEsIGFlcyh4PSIiLCB5PXN1bSwgZmlsbD1OaWRpZmljYXRpb24pKSArDQogICAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCB3aWR0aD0wLjEpICsNCiAgICBjb29yZF9wb2xhcigieSIsIHN0YXJ0PTApICsNCiAgICBnZ3RpdGxlKHBhc3RlKCJTdGF0aW9uOiAiLCBhcy5jaGFyYWN0ZXIodGl0bGUpKSkgKw0KICAgIHRoZW1lX3ZvaWQoKQ0KfQ0KDQojT24gam9pbiBsZXMgZGV1eCB0YWJsZXMgY2l0ZSBldCBkZW5vbWJyZW1lbnRDYXJ0ZQ0KDQpOIDwtIGxlbmd0aCh1bmlxdWUoZGVub21icmVtZW50JENvZGVfTWFpbGxlKSkNCnAgPC0gdmVjdG9yKCJsaXN0IiwgbGVuZ3RoID0gTikNCg0KZm9yIChpIGluIDE6Tikgew0KICAgIGRhdGEgPC0gZGVub21icmVtZW50W3doaWNoKGRlbm9tYnJlbWVudCRDb2RlX01haWxsZSA9PSB1bmlxdWUoZGVub21icmVtZW50JENvZGVfTWFpbGxlKVtpXSksXQ0KICAgIGRhdGEgPC0gZGF0YSAlPiUgZ3JvdXBfYnkoTmlkaWZpY2F0aW9uKSAlPiUgc3VtbWFyaXNlKHN1bSA9IHN1bShwLCBuYS5ybSA9IFRSVUUpKQ0KICAgIHBbW2ldXSA8LSBwbG90X2RhdGEoZGF0YSwgdW5pcXVlKGRlbm9tYnJlbWVudCROb21fbGlldSlbaV0pDQp9DQoNCmNvb3JkaW5hdGVzIDwtIHN0X2FzX3NmKExVUCwgY29vcmRzID0gYygiWCIsICJZIiksIGNycyA9IDIxNTQpDQpjb29yZGluYXRlcyA8LSBzdF90cmFuc2Zvcm0oY29vcmRpbmF0ZXMsIGNycyA9IDQzMjYpDQpjb29yZGluYXRlcyA8LSBjb29yZGluYXRlc1tjb29yZGluYXRlcyRCdWZmZXJTaXplID09IDUwMCxdDQoNCiMgUmVtb3ZlIHRoZSBjb29yZGluYXRlcyB0aGF0IGFyZSBub3QgaW4gZGVub21icmVtZW50DQpmb3IgKGkgaW4gc2VxX2Fsb25nKGNvb3JkaW5hdGVzJElEKSl7DQogIGlmICghKGNvb3JkaW5hdGVzJElEW2ldICVpbiUgdW5pcXVlKGRlbm9tYnJlbWVudCRDb2RlX01haWxsZSkpKXsNCiAgICBjb29yZGluYXRlcyA8LSBjb29yZGluYXRlc1staSxdDQogIH0NCn0NCg0KY29vcmRpbmF0ZXMgPC0gY29vcmRpbmF0ZXNbb3JkZXIoY29vcmRpbmF0ZXMkSUQsIGRlY3JlYXNpbmcgPSBUUlVFKSxdDQoNCnBhbCA8LSBjb2xvck51bWVyaWMoInZpcmlkaXMiLCBkb21haW4gPSBjb29yZGluYXRlcyRNT1MxMSkNCmxlYWZsZXQoZGF0YSA9IGNvb3JkaW5hdGVzKSAlPiUNCiAgYWRkUHJvdmlkZXJUaWxlcygiQ2FydG9EQi5Qb3NpdHJvbiIpICU+JQ0KICBhZGRDaXJjbGVzKHJhZGl1cyA9IDMwMCwgY29sb3IgPSB+cGFsKE1PUzExKSwgDQogICAgICAgICAgICAgZmlsbE9wYWNpdHkgPSAwLjUsIGdyb3VwID0gInBudDIiKSAlPiUNCiAgYWRkTGVnZW5kKCJib3R0b21yaWdodCIsIHBhbCA9IHBhbCwgdmFsdWVzID0gY29vcmRpbmF0ZXMkTU9TMTEsIHRpdGxlID0gIk1PUzExIikgJT4lDQogIGFkZFNjYWxlQmFyKHBvc2l0aW9uID0gImJvdHRvbWxlZnQiKSAlPiUgDQogIGFkZFBvcHVwR3JhcGhzKHAsIHdpZHRoID0gMjAwLCBoZWlnaHQgPSAyMDAsIGdyb3VwID0gInBudDIiKQ0KYGBgDQoNCkNldHRlIGNhcnRlIGlsbHVzdHJlIGxhIHLDqXBhcnRpdGlvbiBkZXMgdHlwZXMgZGUgbmlkaWZpY2F0aW9uIGVuIGZvbmN0aW9uIGRlcyB6b25lcyBnw6lvZ3JhcGhpcXVlcy4gSWwgZXN0IG9ic2VydsOpIHF1ZSBkYW5zIGxlcyB6b25lcyBjZW50cmFsZXMsIGxhIG1ham9yaXTDqSBkZXMgbmlkcyBzb250IHNpdHXDqXMgZGFucyBkZXMgY2F2aXTDqXMsIGNlIHF1aSBwZXV0IMOqdHJlIGF0dHJpYnXDqSDDoCBsYSBkZW5zaXTDqSDDqWxldsOpZSBkZSBiw6J0aW1lbnRzIGV0IMOgIGxhIHJhcmV0w6kgZGUgbGEgdsOpZ8OpdGF0aW9uIGVuIHZpbGxlLiBMZSBtb2RlIGRlIG5pZGlmaWNhdGlvbiBhdSBzb2wgZXN0IGxlIG1vaW5zIGNvdXJhbnQgZGFucyBjZXMgem9uZXMsIHByb2JhYmxlbWVudCBlbiByYWlzb24gZGUgbGEgZmFpYmxlIHByb2JhYmlsaXTDqSBkZSBzdXJ2aWUgZGVzIG9pc2VhdXggZGFucyB1biBlbnZpcm9ubmVtZW50IHVyYmFpbiBhdmVjIHVuIG5pZCBhdSBzb2wuICANCg0KRW4gcMOpcmlwaMOpcmllLCBsZXMgbW9kZXMgZGUgbmlkaWZpY2F0aW9uIHNlbWJsZW50IHBsdXMgZGl2ZXJzaWZpw6lzLCBhdmVjIHVuZSBwcsOpZG9taW5hbmNlIGRlIGxhIG5pZGlmaWNhdGlvbiBlbiBidWlzc29uLiBMYSBuaWRpZmljYXRpb24gZGFucyBsZXMgYXJicmVzIGVzdCDDqWdhbGVtZW50IHRyw6hzIHLDqXBhbmR1ZSwgZXQgb24gcmV0cm91dmUgYXVzc2kgbGEgbmlkaWZpY2F0aW9uIGVuIGNhdml0w6kuIExlIGZhaXQgZGUgbmUgcGFzIMOqdHJlIHNpdHXDqSBkaXJlY3RlbWVudCBhdSBjZW50cmUtdmlsbGUgc2VtYmxlIG9mZnJpciBwbHVzIGRlIHBvc3NpYmlsaXTDqXMgZGUgbmlkaWZpY2F0aW9uLCBjZSBxdWkgcG91cnJhaXQgZXhwbGlxdWVyIHVuZSBwbHVzIGdyYW5kZSBkaXZlcnNpdMOpIGQnZXNww6hjZXMgc2kgb24gcyfDqWxvaWduZSBsw6lnw6hyZW1lbnQgZHUgY2VudHJlIHZpbGxlLCBncsOiY2Ugw6AgdW5lIGNvbWJpbmFpc29uIGRlIGLDonRpbWVudHMgZXQgZGUgdsOpZ8OpdGF0aW9uIG9mZnJhbnQgcGx1cyBkZSBjaG9peCBwb3VyIGxhIG5pZGlmaWNhdGlvbi4NCg0KIyBQb3VyIGFsbGVyIHBsdXMgbG9pbg0KDQpDZXR0ZSBzZWN0aW9uIGVzdCBkw6lkacOpZSDDoCBkZXMgYW5hbHlzZXMgcGx1cyBwb3Vzc8OpZXMgcXVpIHBvdXJyYWllbnQgw6p0cmUgcsOpYWxpc8OpZXMgcG91ciBtaWV1eCBjb21wcmVuZHJlIGxlcyBkb25uw6llcyBldCBsZXMgcmVsYXRpb25zIGVudHJlIGxlcyBkaWZmw6lyZW50ZXMgdmFyaWFibGVzLg0KVm91cyB0cm91dmVyZXogdW4gUGFyYWxsZWwgQ29vcmRpbmF0ZXMgUGxvdCBhaW5zaSBxdSd1biBzdW4gYnVyc3QgcGxvdCBxdWkgaWxsdXN0cmVudCBsZXMgY2FyYWN0w6lyaXN0aXF1ZXMgZGVzIGRpZmbDqXJlbnRlcyBlc3DDqGNlcyBkJ29pc2VhdXguDQoNClZvaWNpLCBjaS1kZXNzb3VzIGxlIFBhcmFsbGVsIENvb3JkaW5hdGVzIFBsb3QgaW50w6lyYWN0aWYuDQpWb3VzIHBvdXZleiBjbGlxdWVyIHN1ciBsZXMgZGlmZsOpcmVudGVzIGVzcMOoY2VzIHBvdXIgb2J0ZW5pciBwbHVzIGQnaW5mb3JtYXRpb25zIHN1ciBjaGFjdW5lIGQnZWxsZXMuDQoNCmBgYHtyfQ0KIyAtLS0gTG9hZCBkYXRhIC0tLQ0KDQpiaXJkc19pbmZvIDwtIHJlYWQuY3N2KCJkYXRhL2JpcmRzL3RyYWl0cy1zdGF0dXQtSVVDTi1iaW9kaXZlcmNpdGUuY3N2IiwgaGVhZGVyID0gVFJVRSkNCmJpcmRzX2luZm8gPC0gYmlyZHNfaW5mb1ssIGMoDQogICJOb20ubGF0aW4iLA0KICAiTml2ZWF1LmRlLnNww6ljaWFsaXNhdGlvbiIsDQogICJSw6lnaW1lLmFsaW1lbnRhaXJlIiwNCiAgIlRlY2huaXF1ZS5kLmFsaW1lbnRhdGlvbiIsDQogICJOaWRpZmljYXRpb24iLA0KICAiUMOpcmlvZGUuZGUubWlncmF0aW9uIg0KKV0NCg0KIyAtLS0gUGFyY29vcmRzIGRhdGEgcHJlcGFyYXRpb24gLS0tDQoNCnVuaXF1ZV9sZXZlbCA8LSB1bmlxdWUoYmlyZHNfaW5mb1ssICJOaXZlYXUuZGUuc3DDqWNpYWxpc2F0aW9uIl0pDQp1bmlxdWVfcmVnaW1lIDwtIHVuaXF1ZShiaXJkc19pbmZvWywgIlLDqWdpbWUuYWxpbWVudGFpcmUiXSkNCnVuaXF1ZV90ZWNobmlxdWUgPC0gdW5pcXVlKGJpcmRzX2luZm9bLCAiVGVjaG5pcXVlLmQuYWxpbWVudGF0aW9uIl0pDQp1bmlxdWVfbmlkaSA8LSB1bmlxdWUoYmlyZHNfaW5mb1ssICJOaWRpZmljYXRpb24iXSkNCnVuaXF1ZV9taWdyYXRpb24gPC0gdW5pcXVlKGJpcmRzX2luZm9bLCAiUMOpcmlvZGUuZGUubWlncmF0aW9uIl0pDQoNCnBsb3RfbHkoZGF0YS5mcmFtZSgpLCB0eXBlID0gInBhcmNvb3JkcyIsIGxpbmUgPSBsaXN0KGNvbG9yID0gImJsdWUiKSwgaGVpZ2h0ID0gOTUwLA0KICBkaW1lbnNpb25zID0gbGlzdCgNCiAgICBsaXN0KA0KICAgICAgbGFiZWwgPSAiRXNww6hjZXMiLA0KICAgICAgcmFuZ2UgPSBjKDAsIGxlbmd0aChiaXJkc19pbmZvWywgIk5vbS5sYXRpbiJdKSArIDEpLA0KICAgICAgdGlja3ZhbHMgPSAxOmxlbmd0aChiaXJkc19pbmZvWywgIk5vbS5sYXRpbiJdKSwNCiAgICAgIHRpY2t0ZXh0ID0gYmlyZHNfaW5mb1ssICJOb20ubGF0aW4iXSwNCiAgICAgIHZhbHVlcyA9IDE6bGVuZ3RoKGJpcmRzX2luZm9bLCAiTm9tLmxhdGluIl0pDQogICAgKSwNCiAgICBsaXN0KA0KICAgICAgbGFiZWwgPSAiVGVjaG5pcXVlIGQnYWxpbWVudGF0aW9uIiwNCiAgICAgIHJhbmdlID0gYygwLCBsZW5ndGgodW5pcXVlX3RlY2huaXF1ZSkgKyAxKSwNCiAgICAgIHRpY2t2YWxzID0gYXMubnVtZXJpYyhmYWN0b3IodW5pcXVlX3RlY2huaXF1ZSkpLA0KICAgICAgdGlja3RleHQgPSB1bmlxdWVfdGVjaG5pcXVlLA0KICAgICAgdmFsdWVzID0gYXMubnVtZXJpYyhmYWN0b3IoYmlyZHNfaW5mb1ssICJUZWNobmlxdWUuZC5hbGltZW50YXRpb24iXSkpDQogICAgKSwNCiAgICBsaXN0KA0KICAgICAgbGFiZWwgPSAiTmlkaWZpY2F0aW9uIiwNCiAgICAgIHJhbmdlID0gYygwLCBsZW5ndGgodW5pcXVlX25pZGkpICsgMSksDQogICAgICB0aWNrdmFscyA9IGFzLm51bWVyaWMoZmFjdG9yKHVuaXF1ZV9uaWRpKSksDQogICAgICB0aWNrdGV4dCA9IHVuaXF1ZV9uaWRpLA0KICAgICAgdmFsdWVzID0gYXMubnVtZXJpYyhmYWN0b3IoYmlyZHNfaW5mb1ssICJOaWRpZmljYXRpb24iXSkpDQogICAgKSwNCiAgICBsaXN0KA0KICAgICAgbGFiZWwgPSAiTml2ZWF1IGRlIHNww6ljaWFsaXNhdGlvbiIsDQogICAgICByYW5nZSA9IGMoMCwgbGVuZ3RoKHVuaXF1ZV9sZXZlbCkgKyAxKSwNCiAgICAgIHRpY2t2YWxzID0gYXMubnVtZXJpYyhmYWN0b3IodW5pcXVlX2xldmVsKSksDQogICAgICB0aWNrdGV4dCA9IHVuaXF1ZV9sZXZlbCwNCiAgICAgIHZhbHVlcyA9IGFzLm51bWVyaWMoZmFjdG9yKGJpcmRzX2luZm9bLCAiTml2ZWF1LmRlLnNww6ljaWFsaXNhdGlvbiJdKSkNCiAgICApLA0KICAgIGxpc3QoDQogICAgICBsYWJlbCA9ICJQw6lyaW9kZSBkZSBtaWdyYXRpb24iLA0KICAgICAgcmFuZ2UgPSBjKDAsIGxlbmd0aCh1bmlxdWVfbWlncmF0aW9uKSArIDEpLA0KICAgICAgdGlja3ZhbHMgPSBhcy5udW1lcmljKGZhY3Rvcih1bmlxdWVfbWlncmF0aW9uKSksDQogICAgICB0aWNrdGV4dCA9IHVuaXF1ZV9taWdyYXRpb24sDQogICAgICB2YWx1ZXMgPSBhcy5udW1lcmljKGZhY3RvcihiaXJkc19pbmZvWywgIlDDqXJpb2RlLmRlLm1pZ3JhdGlvbiJdKSkNCiAgICApLA0KICAgIGxpc3QoDQogICAgICBsYWJlbCA9ICJSw6lnaW1lIGFsaW1lbnRhaXJlIiwNCiAgICAgIHJhbmdlID0gYygwLCBsZW5ndGgodW5pcXVlX3JlZ2ltZSkgKyAxKSwNCiAgICAgIHRpY2t2YWxzID0gYXMubnVtZXJpYyhmYWN0b3IodW5pcXVlX3JlZ2ltZSkpLA0KICAgICAgdGlja3RleHQgPSB1bmlxdWVfcmVnaW1lLA0KICAgICAgdmFsdWVzID0gYXMubnVtZXJpYyhmYWN0b3IoYmlyZHNfaW5mb1ssICJSw6lnaW1lLmFsaW1lbnRhaXJlIl0pKQ0KICAgICkNCiAgKQ0KKSAlPiUgbGF5b3V0KA0KICB0aXRsZSA9ICJDYXJhY3TDqXJpc3RpcXVlcyBkZXMgZGlmZsOpcmVudGVzIGVzcMOoY2VzIGQnb2lzZWF1eCIsDQogIG1hcmdpbiA9IGxpc3QobCA9IDE0MCwgciA9IDU1LCBiID0gMCkNCikNCmBgYA0KDQojIyMgRXhlbXBsZSBkJ3V0aWxpc2F0aW9uIDoNCg0KLSBOb3VzIHZvdWxvbnMgc2F2b2lyIGxlIHLDqWdpbWUgYWxpbWVudGFpcmUgZGVzIG9pc2VhdXggcXVpIG1pZ3JlbnQuIA0KUG91ciBjZWxhLCBpbCBzdWZmaXQgZGUgY2xpcXVlciBhdSBuaXZlYXUgZGUgIm1pZ3JhdGV1ciB0YXJkaWYiIGV0IGRlIGNsaXF1ZXIgc3VyICJWw6lnw6l0YXJpZW4iLCAiTWl4dGUiIG91ICJjYXJuaXZvcmUiIHBvdXIgb2J0ZW5pciBsZXMgZXNww6hjZXMgZCdvaXNlYXV4IHF1aSBjb3JyZXNwb25kZW50IMOgIGNlcyBjcml0w6hyZXMuDQpDZWNpIGVzdCB0csOocyB1dGlsZSBsb3JzcXUnb24gdmV1dCBjb21wYXJlciBsZSBub21icmUgZCdvaXNlYXUgc2Vsb24gbGVzIGNhcmFjdMOpcmlzdGlxdWVzIGNob2lzaWVzIG91IG3Dqm1lIHNpbXBsZW1lbnQgcmVjaGVyY2hlciBsJ2VzcMOoY2UgcXVpIGNvcnJlc3BvbmQgw6AgY2VydGFpbnMgY3JpdMOocmVzIHF1ZSBsJ29uIHZldXQgw6l0dWRpZXIuDQpQb3VyIGZpbmlyIGwnZXhlbXBsZSwgc2kgb24gY2xpcXVlIGF1IG5pdmVhdSBkZSAiTWlncmF0ZXVyIHRhcmRpZiIsIG9uIHJlbWFycXVlIHF1J2F1Y3VuIG9pc2VhdSBuJ2VzdCB2w6lnw6l0YXJpZW4uDQpEZSBwbHVzLCBvbiBwZXV0IGFmZmluZXIgbm90cmUgc8OpbGVjdGlvbiBwb3VyIHZvaXIgcXVlbGxlcyBlc3DDqGNlcyBkJ29pc2VhdXggc29udCBkZXMgbWlncmF0ZXVycyB0YXJkaWZzIGV0IGZvbnQgbGV1ciBuaWQgZGFucyBsZXMgYnVpc3NvbnMuDQpPbiBjbGlxdWUgYWluc2kgc3VyIGJ1aXNzb24gZXQgb24gdm9pdCBxdWUgbCdlc3DDqGNlICJMYW5pdXMgY29sbHVyaW8iIGNvcnJlc3BvbmQgw6AgY2VzIGNyaXTDqHJlcy4NCkMnZXN0IHVuZSBlc3DDqGNlIGNhcm5pdm9yZSBxdWkgbWlncmUgdGFyZGl2ZW1lbnQgZXQgZmFpdCBzb24gbmlkIGRhbnMgbGVzIGJ1aXNzb25zIHF1aSBhIHVuIG5pdmVhdSBkZSBzcMOpY2lhbGlzYXRpb24gYWdyaWNvbGUgZXQgcXVpIHMnYWxpbWVudGUgZW4gdm9sLg0KDQo8Y2VudGVyPg0KICAhW1ZvaWNpIHVuZSBpbWFnZSBkZSBsYSBwaWUtZ3Jpw6hjaGUgw6ljb3JjaGV1ciAoTGFuaXVzIGNvbGx1cmlvKSwgd2lraXBlZGlhXShodHRwczovL3VwbG9hZC53aWtpbWVkaWEub3JnL3dpa2lwZWRpYS9jb21tb25zL2IvYjAvTGFuaXVzX2NvbGx1cmlvXzUuanBnKQ0KPC9jZW50ZXI+DQoNCmBgYHtyfQ0KIyAtLS0gTG9hZCBkYXRhIC0tLQ0KDQpMVVAgPC0gcmVhZC5jc3YoImRhdGEvYmlyZHMvTGFuZFVzZVBlcl9CTV8yMDIzX2NhcnRvSVNlYS5jc3YiLCBoZWFkZXIgPSBUUlVFKQ0KTFVQIDwtIExVUFssIGMoYygiSUQiLCAiQnVmZmVyU2l6ZSIpLCBwYXN0ZTAoIk1PUyIsIDE6MTQpKV0NCg0KYmlyZHNfb2JzIDwtIHJlYWQuY3N2KCJkYXRhL2JpcmRzL09pc2VhdXhfdXBfdG9fMjAyMy5jc3YiLCBoZWFkZXIgPSBUUlVFLCBzZXAgPSAiXHQiKQ0KYmlyZHNfb2JzIDwtIGJpcmRzX29ic1ssIGMoYygiQ29kZV9NYWlsbGUiLCAiRGF0ZSIsICJOb21fVGF4b25fQ2l0ZSIsICJEZW5vbWJyZW1lbnRfbWluIikpXQ0KYmlyZHNfb2JzIDwtIGJpcmRzX29icyAlPiUNCiAgcmVuYW1lKFllYXIgPSBEYXRlLCBJRCA9IENvZGVfTWFpbGxlLCBMYXRpbiA9IE5vbV9UYXhvbl9DaXRlKQ0KDQpiaXJkc19vYnNbLCAiWWVhciJdIDwtIHN1YnN0cihiaXJkc19vYnNbLCAiWWVhciJdLCBzdGFydCA9IDEsIHN0b3AgPSA0KQ0KYmlyZHNfb2JzWywgIkxhdGluIl0gPC0gc2FwcGx5KHN0cnNwbGl0KGJpcmRzX29ic1ssICJMYXRpbiJdLCBzcGxpdCA9ICIgfCAiLCBmaXhlZCA9IFRSVUUpLCBmdW5jdGlvbih4KSB4WzFdKQ0KDQpiaXJkc19vYnMgPC0gYmlyZHNfb2JzICU+JQ0KICBncm91cF9ieShJRCwgWWVhciwgTGF0aW4pICU+JQ0KICBzdW1tYXJpc2UoU3VtID0gc3VtKERlbm9tYnJlbWVudF9taW4pLCAuZ3JvdXBzID0gImRyb3AiKQ0KDQpMVVBfYmlyZHNfb2JzIDwtIG1lcmdlKExVUCwgYmlyZHNfb2JzLCBieSA9ICJJRCIpDQoNCiMgLS0tIFN1bmJ1cnN0IGRhdGEgcHJlcGFyYXRpb24gLS0tDQoNCnVuaXF1ZV95ZWFyIDwtIHVuaXF1ZShMVVBfYmlyZHNfb2JzWywgIlllYXIiXSkNCnVuaXF1ZV95ZWFyIDwtIHVuaXF1ZV95ZWFyW29yZGVyKHVuaXF1ZV95ZWFyKV0NCg0KaWRzIDwtIGMoIkFubsOpZSIsIHVuaXF1ZV95ZWFyKQ0KZm9yICh5ZWFyIGluIHVuaXF1ZV95ZWFyKSB7DQogIGlkcyA8LSBjKGlkcywgcGFzdGUwKHllYXIsIHBhc3RlMCgiIC0gTU9TIiwgMToxNCkpKQ0KfQ0KDQpmb3IgKHllYXIgaW4gdW5pcXVlX3llYXIpIHsNCiAgZm9yIChtb3MgaW4gcGFzdGUwKCJNT1MiLCAxOjE0KSkgew0KICAgIGZvciAoc3BlY2llIGluIGJpcmRzX2luZm9bLCAiTm9tLmxhdGluIl0pIHsNCiAgICAgIGlkcyA8LSBjKGlkcywgcGFzdGUwKHllYXIsIHBhc3RlMChwYXN0ZTAoIiAtICIsIG1vcyksIHBhc3RlMCgiIC0gIiwgc3BlY2llKSkpKQ0KICAgIH0NCiAgfQ0KfQ0KDQpsYWJlbHMgPC0gYygiQW5uw6llIiwgdW5pcXVlX3llYXIsIHJlcChwYXN0ZTAoIk1PUyIsIDE6MTQpLCB0aW1lcyA9IGxlbmd0aCh1bmlxdWVfeWVhcikpKQ0KbGFiZWxzIDwtIGMobGFiZWxzLCByZXAoYmlyZHNfaW5mb1ssICJOb20ubGF0aW4iXSwgdGltZXMgPSAxNCAqIGxlbmd0aCh1bmlxdWVfeWVhcikpKQ0KDQpwYXJlbnRzIDwtIGMoIiIsIHJlcCgiQW5uw6llIiwgdGltZXMgPSBsZW5ndGgodW5pcXVlX3llYXIpKSwgcmVwKHVuaXF1ZV95ZWFyLCBlYWNoID0gMTQpKQ0KZm9yICh5ZWFyIGluIHVuaXF1ZV95ZWFyKSB7DQogIHBhcmVudHMgPC0gYyhwYXJlbnRzLCBwYXN0ZTAoeWVhciwgcmVwKHBhc3RlMCgiIC0gTU9TIiwgMToxNCksIGVhY2ggPSBsZW5ndGgoYmlyZHNfaW5mb1ssICJOb20ubGF0aW4iXSkpKSkNCn0NCg0KdmFsdWVzIDwtIGMoYyhsZW5ndGgodW5pcXVlX3llYXIpICogMTQwMDAsIHJlcCgxNDAwMCwgdGltZXMgPSBsZW5ndGgodW5pcXVlX3llYXIpKSksIHJlcCgxMDAwLCB0aW1lcyA9IGxlbmd0aCh1bmlxdWVfeWVhcikgKiAxNCkpDQpmb3IgKHllYXIgaW4gdW5pcXVlX3llYXIpIHsNCiAgZm9yIChtb3MgaW4gcGFzdGUwKCJNT1MiLCAxOjE0KSkgew0KICAgIGZvciAoc3BlY2llIGluIGJpcmRzX2luZm9bLCAiTm9tLmxhdGluIl0pIHsNCiAgICAgIHRtcCA8LSBMVVBfYmlyZHNfb2JzW0xVUF9iaXJkc19vYnNbIlllYXIiXSA9PSB5ZWFyICYgTFVQX2JpcmRzX29ic1siTGF0aW4iXSA9PSBzcGVjaWUgJiBMVVBfYmlyZHNfb2JzWyJCdWZmZXJTaXplIl0gPT0gNTAwLCBdDQogICAgICB2YWx1ZXMgPC0gYyh2YWx1ZXMsIHN1bSh0bXBbbW9zXSAqIHRtcFsiU3VtIl0pKQ0KICAgIH0NCiAgICB0YWlsX3ZhbHVlcyA8LSB2YWx1ZXNbKDEgKyBsZW5ndGgodmFsdWVzKSAtIGxlbmd0aChiaXJkc19pbmZvWywgIk5vbS5sYXRpbiJdKSk6bGVuZ3RoKHZhbHVlcyldDQogICAgdmFsdWVzWygxICsgbGVuZ3RoKHZhbHVlcykgLSBsZW5ndGgoYmlyZHNfaW5mb1ssICJOb20ubGF0aW4iXSkpOmxlbmd0aCh2YWx1ZXMpXSA8LSB0YWlsX3ZhbHVlcyAvIHN1bSh0YWlsX3ZhbHVlcykgKiAxMDAwDQogIH0NCn0NCg0KaXNfbmFuX3ZhbHVlcyA8LSAhaXMubmEodmFsdWVzKSAmIHZhbHVlcyAhPSAwDQppZHMgPC0gaWRzW2lzX25hbl92YWx1ZXNdDQpsYWJlbHMgPC0gbGFiZWxzW2lzX25hbl92YWx1ZXNdDQpwYXJlbnRzIDwtIHBhcmVudHNbaXNfbmFuX3ZhbHVlc10NCnZhbHVlcyA8LSB2YWx1ZXNbaXNfbmFuX3ZhbHVlc10NCg0KIyAtLS0gU3VuYnVyc3QgZGlzcGxheSAtLS0NCg0KcGxvdF9seSgNCiAgaWRzID0gaWRzLA0KICBsYWJlbHMgPSBsYWJlbHMsDQogIHBhcmVudHMgPSBwYXJlbnRzLA0KICB2YWx1ZXMgPSB2YWx1ZXMsDQogIHR5cGUgPSAic3VuYnVyc3QiLA0KICBicmFuY2h2YWx1ZXMgPSAidG90YWwiLA0KICBtYXhkZXB0aCA9IDIsDQogIGluc2lkZXRleHRvcmllbnRhdGlvbiA9ICJyYWRpYWwiLA0KICBob3ZlcmluZm8gPSAibGFiZWwrcGVyY2VudCBlbnRyeSIsDQogIGhlaWdodCA9IDgwMA0KKSAlPiUgbGF5b3V0KA0KICB0aXRsZSA9IGxpc3QoDQogICAgdGV4dCA9ICJQcm9wb3J0aW9uIGRlcyBlc3DDqGNlcyBkJ29pc2VhdXggbGVzIHBsdXMgY291cmFtbWVudCBvYnNlcnbDqWVzPGJyPmVuIGZvbmN0aW9uIGRlIGwnYW5uw6llIGV0IGR1IE1PUyIsDQogICAgeSA9IDEuMQ0KICApLA0KICBtYXJnaW4gPSBsaXN0KHQgPSAxMDApDQopDQpgYGANCg0KIyBDb25jbHVzaW9uDQoNCg0KQXByw6hzIGF2b2lyIG1lbsOpIHVuZSDDqXR1ZGUgYXBwcm9mb25kaWUgc3VyIGxhIGRpdmVyc2l0w6kgZGVzIG9pc2VhdXggw6AgQm9yZGVhdXggZXQgc2EgcMOpcmlwaMOpcmllLCBub3VzIGF2b25zIHB1IGZhaXJlIHBsdXNpZXVycyBkw6ljb3V2ZXJ0ZXMgaW50w6lyZXNzYW50ZXMgZW4gdXRpbGlzYW50IGRpZmbDqXJlbnRlcyBtZXN1cmVzIGRlIGRpdmVyc2l0w6kgdGVsbGVzIHF1ZSBsYSByaWNoZXNzZSBzcMOpY2lmaXF1ZSwgbCdpbmRpY2UgZGUgU2hhbm5vbiBldCBsJ2luZGljZSBkZSBTaW1wc29uLg0KDQpUb3V0IGQnYWJvcmQsIG5vdXMgYXZvbnMgZMOpY291dmVydCBxdWUgbGEgZGl2ZXJzaXTDqSBkZXMgZXNww6hjZXMgZCdvaXNlYXV4IGVzdCDDqXRyb2l0ZW1lbnQgbGnDqWUgYXUgbml2ZWF1IGQnYXJ0aWZpY2lhbGlzYXRpb24gZGVzIHNvbHMsIG1lc3Vyw6kgcGFyIGxhIHZhcmlhYmxlIE1PUzExLiBFbiBlZmZldCwgbm91cyBhdm9ucyBjb25zdGF0w6kgcXVlIGxhIGRpdmVyc2l0w6kgZXN0IHBsdXMgw6lsZXbDqWUgZGFucyBsZXMgem9uZXMgb8O5IHNlIG3DqWxhbmdlbnQgZXNwYWNlcyB2ZXJ0cyBldCB6b25lcyB1cmJhbmlzw6llcy4gQ2V0dGUgb2JzZXJ2YXRpb24gc3VnZ8OocmUgcXVlIGxlcyB6b25lcyB1cmJhaW5lcyBxdWkgcHLDqXNlcnZlbnQgZGVzIGVzcGFjZXMgdmVydHMgZXQgZGVzIGhhYml0YXRzIG5hdHVyZWxzIHNvbnQgcGx1cyBzdXNjZXB0aWJsZXMgZCdhY2N1ZWlsbGlyIHVuZSBncmFuZGUgZGl2ZXJzaXTDqSBkJ2VzcMOoY2VzIGQnb2lzZWF1eC4NCg0KRW5zdWl0ZSwgbm91cyBhdm9ucyDDqXR1ZGnDqSBsYSByZWxhdGlvbiBlbnRyZSBsYSBkaXZlcnNpdMOpIGRlcyBlc3DDqGNlcyBkJ29pc2VhdXggZXQgbGEgZGlzdGFuY2UgYXUgY2VudHJlLXZpbGxlLiBOb3VzIGF2b25zIGNvbnN0YXTDqSBxdWUgbGEgZGl2ZXJzaXTDqSBlc3QgcGx1cyBncmFuZGUgbG9yc3F1ZSBsYSBtYWlsbGUgc2UgdHJvdXZlIMOgIGVudmlyb24gOSBrbSBkdSBjZW50cmUtdmlsbGUuIENldHRlIHRlbmRhbmNlIHMnZXhwbGlxdWUgZW4gcGFydGllIHBhciBsZSBmYWl0IHF1ZSBsZXMgem9uZXMgc2l0dcOpZXMgw6AgY2V0dGUgZGlzdGFuY2UgZHUgY2VudHJlLXZpbGxlIHNvbnQgc291dmVudCBkZXMgem9uZXMgZGUgdHJhbnNpdGlvbiBlbnRyZSBsZXMgZXNwYWNlcyB1cmJhaW5zIGV0IGxlcyBlc3BhY2VzIHJ1cmF1eCwgb2ZmcmFudCBhaW5zaSB1bmUgdmFyacOpdMOpIGQnaGFiaXRhdHMgcG91ciBsZXMgb2lzZWF1eC4NCg0KUGFyIGxhIHN1aXRlLCBub3VzIGF2b25zIGVzc2F5w6kgZGUgdHJvdXZlciBkZXMgbGllbnMgZW50cmUgbGEgZGl2ZXJzaXTDqSBkZXMgZXNww6hjZXMgZCdvaXNlYXV4IGV0IGQnYXV0cmVzIGNhcmFjdMOpcmlzdGlxdWVzIHRlbGxlcyBxdWUgbGVzIHLDqWdpbWVzIGFsaW1lbnRhaXJlcywgbGVzIG5pdmVhdXggZGUgc3DDqWNpYWxpc2F0aW9uIGV0IGxlcyBtb2RlcyBkZSBuaWRpZmljYXRpb24uDQoNClBvdXIgbGVzIG5pdmVhdXggZGUgc3DDqWNpYWxpc2F0aW9uLCBub3VzIGF2b25zIG9ic2VydsOpIHF1ZSBsZXMgb2lzZWF1eCBkZSB0eXBlIELDonRpIHNvbnQgcGx1cyByw6lwYW5kdXMgZGFucyBsZXMgem9uZXMgdXJiYWluZXMsIHRhbmRpcyBxdWUgbGVzIG9pc2VhdXggZGUgdHlwZSBGb3LDqnQgZXQgQWdyaWNvbGUgc29udCBwbHVzIGZyw6lxdWVudHMgZW4gcMOpcmlwaMOpcmllLiBJbCB5IGF1c3NpIGRlIG5vbWJyZXVzZXMgZXNww6hjZXMgZGUgdHlwZSBab25lIGh1bWlkZSBwcsOocyBkZXMgcG9pbnRzIGQnZWF1LiBJbCB5IGEgZGUgbm9tYnJldXNlcyBlc3DDqGNlcyBnw6luw6lyYWxpc3RlcyBhdSBjZW50cmUtdmlsbGUgZXQgZW4gcMOpcmlwaMOpcmllLiBDZXMgb2JzZXJ2YXRpb25zIHN1Z2fDqHJlbnQgIHF1ZSBsYSBkaXZlcnNpdMOpIGRlcyBlc3DDqGNlcyBlc3QgaW5mbHVlbmPDqWUgcGFyIGxlcyBjYXJhY3TDqXJpc3RpcXVlcyBkZXMgaGFiaXRhdHMuDQoNCk5vdXMgYXZvbnMgw6lnYWxlbWVudCDDqXR1ZGnDqSBsZXMgcsOpZ2ltZXMgYWxpbWVudGFpcmVzIGRlcyBvaXNlYXV4IGV0IGF2b25zIGNvbnN0YXTDqSBxdWUgbGUgcsOpZ2ltZSBhbGltZW50YWlyZSBkZSBsJ29pc2VhdSBuZSBzZW1ibGUgcGFzIMOqdHJlIGltcGFjdMOpIHBhciBsJ2FydGlmaWNpYWxpc2F0aW9uIGRlcyBzb2xzLiBDZXR0ZSBvYnNlcnZhdGlvbiBzdWdnw6hyZSBxdWUgbGVzIG9pc2VhdXggc29udCBjYXBhYmxlcyBkZSBzJ2FkYXB0ZXIgw6AgbGV1ciBlbnZpcm9ubmVtZW50IGV0IGRlIHRyb3V2ZXIgZGUgbGEgbm91cnJpdHVyZSBtw6ptZSBkYW5zIGxlcyB6b25lcyB1cmJhaW5lcy4NCg0KRW5maW4sIG5vdXMgYXZvbnMgw6l0dWRpw6kgbGVzIG1vZGVzIGRlIG5pZGlmaWNhdGlvbiBkZXMgb2lzZWF1eCBldCBhdm9ucyBjb25zdGF0w6kgcXVlIGxlcyB6b25lcyBxdWkgY29tYmluZW50IMOgIGxhIGZvaXMgdsOpZ8OpdGF0aW9uIGV0IGLDonRpbWVudHMgc29udCBwbHVzIHN1c2NlcHRpYmxlcyBkJ2FjY3VlaWxsaXIgZGVzIG9pc2VhdXggYXZlYyBkZXMgbW9kZXMgZGUgbmlkaWZpY2F0aW9uIHZhcmnDqXMuIFBhciBleGVtcGxlLCBsZXMgem9uZXMgY2VudHJhbGVzIHNvbnQgcHJvcGljZXMgw6AgbGEgbmlkaWZpY2F0aW9uIGVuIGNhdml0w6kgZW4gcmFpc29uIGRlIGxhIGRlbnNpdMOpIMOpbGV2w6llIGRlIGLDonRpbWVudHMsIHRhbmRpcyBxdWUgbGVzIHpvbmVzIHDDqXJpcGjDqXJpcXVlcyBvZmZyZW50IHBsdXMgZGUgcG9zc2liaWxpdMOpcyBkZSBuaWRpZmljYXRpb24gZW4gYnVpc3NvbiBldCBkYW5zIGxlcyBhcmJyZXMuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KQ2V0dGUgb2JzZXJ2YXRpb24gc291bGlnbmUgbCdpbXBvcnRhbmNlIGRlIHByw6lzZXJ2ZXIgZXQgZGUgcmVzdGF1cmVyIGxlcyBoYWJpdGF0cyBuYXR1cmVscyBkYW5zIGxlcyB6b25lcyB1cmJhaW5lcyBwb3VyIG1haW50ZW5pciB1biBuaXZlYXUgbWF4aW1hbCBkZSBkaXZlcnNpdMOpIGRlcyBlc3DDqGNlcyBkJ29pc2VhdXguDQoNCkVuIGNvbmNsdXNpb24sIG5vdHJlIMOpdHVkZSBhIHBlcm1pcyBkZSBtZXR0cmUgZW4gw6l2aWRlbmNlIGwnaW1wb3J0YW5jZSBkZSBwcsOpc2VydmVyIGV0IGRlIHJlc3RhdXJlciBsZXMgaGFiaXRhdHMgbmF0dXJlbHMgZGFucyBsZXMgem9uZXMgdXJiYWluZXMgcG91ciBtYWludGVuaXIgbGEgYmlvZGl2ZXJzaXTDqSBkZXMgb2lzZWF1eC4gTm91cyBhdm9ucyBjb25zdGF0w6kgcXVlIGxlcyB6b25lcyBkZSB0cmFuc2l0aW9uIGVudHJlIGxlcyBlc3BhY2VzIHVyYmFpbnMgZXQgcnVyYXV4IHNvbnQgZGVzIHpvbmVzIGNsw6lzIHBvdXIgbGEgZGl2ZXJzaXTDqSBkZXMgZXNww6hjZXMgZCdvaXNlYXV4LiBOb3VzIGF2b25zIMOpZ2FsZW1lbnQgb2JzZXJ2w6kgcXVlIGxlcyBvaXNlYXV4IHNvbnQgY2FwYWJsZXMgZGUgcydhZGFwdGVyIMOgIGxldXIgZW52aXJvbm5lbWVudCBldCBkZSB0cm91dmVyIGRlIGxhIG5vdXJyaXR1cmUgbcOqbWUgZGFucyBsZXMgem9uZXMgdXJiYWluZXMuIENlcyByw6lzdWx0YXRzIHNvdWxpZ25lbnQgbCdpbXBvcnRhbmNlIGRlIHByZW5kcmUgZW4gY29tcHRlIGxhIGJpb2RpdmVyc2l0w6kgZGFucyBsZXMgcG9saXRpcXVlcyBkJ2Ftw6luYWdlbWVudCB1cmJhaW4gZXQgZGUgcHLDqXNlcnZlciBsZXMgaGFiaXRhdHMgbmF0dXJlbHMgcG91ciBtYWludGVuaXIgbGEgZGl2ZXJzaXTDqSBkZXMgZXNww6hjZXMgZCdvaXNlYXV4LiBFbiB1dGlsaXNhbnQgZGlmZsOpcmVudGVzIG1lc3VyZXMgZGUgZGl2ZXJzaXTDqSwgbm91cyBhdm9ucyBwdSBjb25maXJtZXIgY2VzIHLDqXN1bHRhdHMgZXQgcmVuZm9yY2VyIGxhIHZhbGlkaXTDqSBkZSBub3RyZSDDqXR1ZGUuDQoNCmBgYHtyfQ0KbW9zX3RhYmxlIDwtIHJlYWQuY3N2KCJkYXRhL2JpcmRzL3RoZW1lc19tb3NfZ2lyLnR4dCIsIGhlYWRlciA9IFRSVUUsIHNlcCA9ICJcdCIpDQptb3NfdGFibGUgPC0gbW9zX3RhYmxlWywgYygiSUQiLCAiTU9TIildDQptb3NfdGFibGVbIklEIl0gPC0gcGFzdGUwKCJNT1MiLCBtb3NfdGFibGVbLCAiSUQiXSkNCg0KbW9zX3RhYmxlDQpgYGA=